@utsp/core 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/index.cjs +9 -0
- package/dist/index.d.ts +4732 -0
- package/dist/index.mjs +9 -0
- package/package.json +63 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4732 @@
|
|
|
1
|
+
import { Vector2, AxisSource, ButtonSource, InputBindingLoadPacket, AxisBinding, ButtonBinding, UserRenderState } from '@utsp/types';
|
|
2
|
+
export { AxisBinding, AxisSource, ButtonBinding, ButtonSource, InputBindingLoadPacket, RenderState, RenderedCell, UserRenderState, Vector2 } from '@utsp/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Font system for UTSP Core
|
|
6
|
+
* Supports WebFont (CSS-based) and BitmapFont (pixel-based)
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Font type enumeration
|
|
10
|
+
*/
|
|
11
|
+
declare enum FontType {
|
|
12
|
+
Web = "web",
|
|
13
|
+
Bitmap = "bitmap"
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* WebFont configuration
|
|
17
|
+
* For CSS-based fonts rendered by the browser
|
|
18
|
+
*/
|
|
19
|
+
interface WebFontConfig {
|
|
20
|
+
fontFamily: string;
|
|
21
|
+
fontSize: number;
|
|
22
|
+
offsetX?: number;
|
|
23
|
+
offsetY?: number;
|
|
24
|
+
charSpacing?: number;
|
|
25
|
+
lineHeight?: number;
|
|
26
|
+
fontWeight?: string;
|
|
27
|
+
fontStyle?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* WebFont class
|
|
31
|
+
* Represents a CSS-based font for browser rendering
|
|
32
|
+
*/
|
|
33
|
+
declare class WebFont {
|
|
34
|
+
private fontId;
|
|
35
|
+
private config;
|
|
36
|
+
constructor(fontId: number, config: WebFontConfig);
|
|
37
|
+
/**
|
|
38
|
+
* Get the unique font ID
|
|
39
|
+
*/
|
|
40
|
+
getFontId(): number;
|
|
41
|
+
/**
|
|
42
|
+
* Get the full configuration (copy)
|
|
43
|
+
*/
|
|
44
|
+
getConfig(): WebFontConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Get the font family
|
|
47
|
+
*/
|
|
48
|
+
getFontFamily(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Get the font size in pixels
|
|
51
|
+
*/
|
|
52
|
+
getFontSize(): number;
|
|
53
|
+
/**
|
|
54
|
+
* Get the horizontal offset
|
|
55
|
+
*/
|
|
56
|
+
getOffsetX(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Get the vertical offset
|
|
59
|
+
*/
|
|
60
|
+
getOffsetY(): number;
|
|
61
|
+
/**
|
|
62
|
+
* Get the character spacing
|
|
63
|
+
*/
|
|
64
|
+
getCharSpacing(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Get the line height multiplier
|
|
67
|
+
*/
|
|
68
|
+
getLineHeight(): number;
|
|
69
|
+
/**
|
|
70
|
+
* Get the font weight
|
|
71
|
+
*/
|
|
72
|
+
getFontWeight(): string;
|
|
73
|
+
/**
|
|
74
|
+
* Get the font style
|
|
75
|
+
*/
|
|
76
|
+
getFontStyle(): string;
|
|
77
|
+
/**
|
|
78
|
+
* Generate CSS declaration for this font
|
|
79
|
+
* @returns CSS string (e.g., "font-family: Consolas; font-size: 16px;")
|
|
80
|
+
*/
|
|
81
|
+
toCSS(): string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* BitmapFont configuration
|
|
85
|
+
* For pixel-based fonts with custom glyph data
|
|
86
|
+
*/
|
|
87
|
+
interface BitmapFontConfig {
|
|
88
|
+
charWidth: number;
|
|
89
|
+
charHeight: number;
|
|
90
|
+
cellWidth?: number;
|
|
91
|
+
cellHeight?: number;
|
|
92
|
+
glyphs: Map<number, Uint8Array>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* BitmapFont class
|
|
96
|
+
* Represents a pixel-based font with custom glyph bitmaps
|
|
97
|
+
* Corresponds to LoadType 0x04 (Charset) in UTSP protocol
|
|
98
|
+
*/
|
|
99
|
+
declare class BitmapFont {
|
|
100
|
+
private fontId;
|
|
101
|
+
private config;
|
|
102
|
+
constructor(fontId: number, config: BitmapFontConfig);
|
|
103
|
+
/**
|
|
104
|
+
* Get the unique font ID
|
|
105
|
+
*/
|
|
106
|
+
getFontId(): number;
|
|
107
|
+
/**
|
|
108
|
+
* Get the full configuration (deep copy)
|
|
109
|
+
*/
|
|
110
|
+
getConfig(): BitmapFontConfig;
|
|
111
|
+
/**
|
|
112
|
+
* Get the glyph width in pixels (actual bitmap size)
|
|
113
|
+
*/
|
|
114
|
+
getCharWidth(): number;
|
|
115
|
+
/**
|
|
116
|
+
* Get the glyph height in pixels (actual bitmap size)
|
|
117
|
+
*/
|
|
118
|
+
getCharHeight(): number;
|
|
119
|
+
/**
|
|
120
|
+
* Get the target cell width in pixels (rendering size)
|
|
121
|
+
* Defaults to glyph width if not specified
|
|
122
|
+
*/
|
|
123
|
+
getCellWidth(): number;
|
|
124
|
+
/**
|
|
125
|
+
* Get the target cell height in pixels (rendering size)
|
|
126
|
+
* Defaults to glyph height if not specified
|
|
127
|
+
*/
|
|
128
|
+
getCellHeight(): number;
|
|
129
|
+
/**
|
|
130
|
+
* Get the bitmap data for a specific character
|
|
131
|
+
* @param charCode Character code (0-255)
|
|
132
|
+
* @returns Bitmap data or undefined if not found
|
|
133
|
+
*/
|
|
134
|
+
getGlyph(charCode: number): Uint8Array | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Check if a glyph exists for a character
|
|
137
|
+
* @param charCode Character code (0-255)
|
|
138
|
+
*/
|
|
139
|
+
hasGlyph(charCode: number): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Get the number of glyphs in this font
|
|
142
|
+
*/
|
|
143
|
+
getGlyphCount(): number;
|
|
144
|
+
/**
|
|
145
|
+
* Get all character codes that have glyphs
|
|
146
|
+
*/
|
|
147
|
+
getCharCodes(): number[];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Network representation of a display
|
|
152
|
+
* Layers are NO LONGER under displays - they are at User level
|
|
153
|
+
*/
|
|
154
|
+
interface NetworkDisplay {
|
|
155
|
+
/** Display ID (0-255) */
|
|
156
|
+
id: number;
|
|
157
|
+
/** Origin X position in virtual world (0-65535) */
|
|
158
|
+
originX: number;
|
|
159
|
+
/** Origin Y position in virtual world (0-65535) */
|
|
160
|
+
originY: number;
|
|
161
|
+
/** Display width in cells (1-256) */
|
|
162
|
+
sizeX: number;
|
|
163
|
+
/** Display height in cells (1-256) */
|
|
164
|
+
sizeY: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Base interface for all network orders
|
|
169
|
+
*/
|
|
170
|
+
interface NetworkOrder {
|
|
171
|
+
type: number;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 0x01 - Char: Renders a single character at a specific position
|
|
175
|
+
*/
|
|
176
|
+
interface CharOrder extends NetworkOrder {
|
|
177
|
+
type: 0x01;
|
|
178
|
+
posX: number;
|
|
179
|
+
posY: number;
|
|
180
|
+
charCode: number;
|
|
181
|
+
bgColorCode: number;
|
|
182
|
+
fgColorCode: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 0x02 - Text: Renders a string of characters with uniform colors
|
|
186
|
+
*/
|
|
187
|
+
interface TextOrder extends NetworkOrder {
|
|
188
|
+
type: 0x02;
|
|
189
|
+
posX: number;
|
|
190
|
+
posY: number;
|
|
191
|
+
text: string;
|
|
192
|
+
bgColorCode: number;
|
|
193
|
+
fgColorCode: number;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 0x17 - TextMultiline: Renders multiple lines of text (\n for line breaks)
|
|
197
|
+
*/
|
|
198
|
+
interface TextMultilineOrder extends NetworkOrder {
|
|
199
|
+
type: 0x17;
|
|
200
|
+
posX: number;
|
|
201
|
+
posY: number;
|
|
202
|
+
text: string;
|
|
203
|
+
bgColorCode: number;
|
|
204
|
+
fgColorCode: number;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* 0x03 - SubFrame: Renders a rectangular region with uniform colors
|
|
208
|
+
*/
|
|
209
|
+
interface SubFrameOrder extends NetworkOrder {
|
|
210
|
+
type: 0x03;
|
|
211
|
+
posX: number;
|
|
212
|
+
posY: number;
|
|
213
|
+
sizeX: number;
|
|
214
|
+
sizeY: number;
|
|
215
|
+
bgColorCode: number;
|
|
216
|
+
fgColorCode: number;
|
|
217
|
+
frame: number[];
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* 0x04 - SubFrameMultiColor: Rectangular region with per-cell colors
|
|
221
|
+
*/
|
|
222
|
+
interface SubFrameMultiColorOrder extends NetworkOrder {
|
|
223
|
+
type: 0x04;
|
|
224
|
+
posX: number;
|
|
225
|
+
posY: number;
|
|
226
|
+
sizeX: number;
|
|
227
|
+
sizeY: number;
|
|
228
|
+
frame: Array<{
|
|
229
|
+
charCode: number;
|
|
230
|
+
bgColorCode: number;
|
|
231
|
+
fgColorCode: number;
|
|
232
|
+
}>;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 0x05 - FullFrame: Renders entire screen with uniform colors
|
|
236
|
+
*/
|
|
237
|
+
interface FullFrameOrder extends NetworkOrder {
|
|
238
|
+
type: 0x05;
|
|
239
|
+
bgColorCode: number;
|
|
240
|
+
fgColorCode: number;
|
|
241
|
+
frame: number[];
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 0x06 - FullFrameMultiColor: Entire screen with per-cell colors
|
|
245
|
+
*/
|
|
246
|
+
interface FullFrameMultiColorOrder extends NetworkOrder {
|
|
247
|
+
type: 0x06;
|
|
248
|
+
frame: Array<{
|
|
249
|
+
charCode: number;
|
|
250
|
+
bgColorCode: number;
|
|
251
|
+
fgColorCode: number;
|
|
252
|
+
}>;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* 0x07 - Sprite: Renders a preloaded unicolor sprite
|
|
256
|
+
*/
|
|
257
|
+
interface SpriteOrder extends NetworkOrder {
|
|
258
|
+
type: 0x07;
|
|
259
|
+
posX: number;
|
|
260
|
+
posY: number;
|
|
261
|
+
spriteIndex: number;
|
|
262
|
+
bgColorCode: number;
|
|
263
|
+
fgColorCode: number;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* 0x08 - SpriteMultiColor: Renders a preloaded multicolor sprite
|
|
267
|
+
*/
|
|
268
|
+
interface SpriteMultiColorOrder extends NetworkOrder {
|
|
269
|
+
type: 0x08;
|
|
270
|
+
posX: number;
|
|
271
|
+
posY: number;
|
|
272
|
+
spriteIndex: number;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* 0x09 - ColorMap: Applies colors to a region without changing characters
|
|
276
|
+
*/
|
|
277
|
+
interface ColorMapOrder extends NetworkOrder {
|
|
278
|
+
type: 0x09;
|
|
279
|
+
posX: number;
|
|
280
|
+
posY: number;
|
|
281
|
+
sizeX: number;
|
|
282
|
+
sizeY: number;
|
|
283
|
+
colorData: Array<{
|
|
284
|
+
bgColorCode: number;
|
|
285
|
+
fgColorCode: number;
|
|
286
|
+
}>;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* 0x0A - Shape: Renders geometric shapes
|
|
290
|
+
*/
|
|
291
|
+
interface ShapeOrder extends NetworkOrder {
|
|
292
|
+
type: 0x0a;
|
|
293
|
+
shapeType: ShapeType;
|
|
294
|
+
shapeData: ShapeData;
|
|
295
|
+
}
|
|
296
|
+
declare enum ShapeType {
|
|
297
|
+
Rectangle = 1,
|
|
298
|
+
Circle = 2,
|
|
299
|
+
Line = 3,
|
|
300
|
+
Ellipse = 4,
|
|
301
|
+
Triangle = 5
|
|
302
|
+
}
|
|
303
|
+
type ShapeData = RectangleShape | CircleShape | LineShape | EllipseShape | TriangleShape;
|
|
304
|
+
interface RectangleShape {
|
|
305
|
+
posX: number;
|
|
306
|
+
posY: number;
|
|
307
|
+
width: number;
|
|
308
|
+
height: number;
|
|
309
|
+
filled: boolean;
|
|
310
|
+
charCode: number;
|
|
311
|
+
bgColorCode: number;
|
|
312
|
+
fgColorCode: number;
|
|
313
|
+
}
|
|
314
|
+
interface CircleShape {
|
|
315
|
+
centerX: number;
|
|
316
|
+
centerY: number;
|
|
317
|
+
radius: number;
|
|
318
|
+
filled: boolean;
|
|
319
|
+
charCode: number;
|
|
320
|
+
bgColorCode: number;
|
|
321
|
+
fgColorCode: number;
|
|
322
|
+
}
|
|
323
|
+
interface LineShape {
|
|
324
|
+
x1: number;
|
|
325
|
+
y1: number;
|
|
326
|
+
x2: number;
|
|
327
|
+
y2: number;
|
|
328
|
+
charCode: number;
|
|
329
|
+
bgColorCode: number;
|
|
330
|
+
fgColorCode: number;
|
|
331
|
+
}
|
|
332
|
+
interface EllipseShape {
|
|
333
|
+
centerX: number;
|
|
334
|
+
centerY: number;
|
|
335
|
+
radiusX: number;
|
|
336
|
+
radiusY: number;
|
|
337
|
+
filled: boolean;
|
|
338
|
+
charCode: number;
|
|
339
|
+
bgColorCode: number;
|
|
340
|
+
fgColorCode: number;
|
|
341
|
+
}
|
|
342
|
+
interface TriangleShape {
|
|
343
|
+
x1: number;
|
|
344
|
+
y1: number;
|
|
345
|
+
x2: number;
|
|
346
|
+
y2: number;
|
|
347
|
+
x3: number;
|
|
348
|
+
y3: number;
|
|
349
|
+
filled: boolean;
|
|
350
|
+
charCode: number;
|
|
351
|
+
bgColorCode: number;
|
|
352
|
+
fgColorCode: number;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 0x0B - DotCloud: Same character at multiple positions (up to 65535)
|
|
356
|
+
*/
|
|
357
|
+
interface DotCloudOrder extends NetworkOrder {
|
|
358
|
+
type: 0x0b;
|
|
359
|
+
charCode: number;
|
|
360
|
+
bgColorCode: number;
|
|
361
|
+
fgColorCode: number;
|
|
362
|
+
positions: Array<{
|
|
363
|
+
posX: number;
|
|
364
|
+
posY: number;
|
|
365
|
+
}>;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* 0x0C - DotCloudMultiColor: Different characters at multiple positions
|
|
369
|
+
*/
|
|
370
|
+
interface DotCloudMultiColorOrder extends NetworkOrder {
|
|
371
|
+
type: 0x0c;
|
|
372
|
+
dots: Array<{
|
|
373
|
+
charCode: number;
|
|
374
|
+
bgColorCode: number;
|
|
375
|
+
fgColorCode: number;
|
|
376
|
+
posX: number;
|
|
377
|
+
posY: number;
|
|
378
|
+
}>;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* 0x0D - SpriteCloud: Same unicolor sprite at multiple positions
|
|
382
|
+
*/
|
|
383
|
+
interface SpriteCloudOrder extends NetworkOrder {
|
|
384
|
+
type: 0x0d;
|
|
385
|
+
spriteIndex: number;
|
|
386
|
+
bgColorCode: number;
|
|
387
|
+
fgColorCode: number;
|
|
388
|
+
positions: Array<{
|
|
389
|
+
posX: number;
|
|
390
|
+
posY: number;
|
|
391
|
+
}>;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* 0x0E - SpriteCloudMultiColor: Same multicolor sprite at multiple positions
|
|
395
|
+
*/
|
|
396
|
+
interface SpriteCloudMultiColorOrder extends NetworkOrder {
|
|
397
|
+
type: 0x0e;
|
|
398
|
+
spriteIndex: number;
|
|
399
|
+
positions: Array<{
|
|
400
|
+
posX: number;
|
|
401
|
+
posY: number;
|
|
402
|
+
}>;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* 0x0F - SpriteCloudVaried: Different unicolor sprites at multiple positions
|
|
406
|
+
*/
|
|
407
|
+
interface SpriteCloudVariedOrder extends NetworkOrder {
|
|
408
|
+
type: 0x0f;
|
|
409
|
+
sprites: Array<{
|
|
410
|
+
spriteIndex: number;
|
|
411
|
+
bgColorCode: number;
|
|
412
|
+
fgColorCode: number;
|
|
413
|
+
posX: number;
|
|
414
|
+
posY: number;
|
|
415
|
+
}>;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* 0x10 - SpriteCloudVariedMultiColor: Different multicolor sprites at multiple positions
|
|
419
|
+
*/
|
|
420
|
+
interface SpriteCloudVariedMultiColorOrder extends NetworkOrder {
|
|
421
|
+
type: 0x10;
|
|
422
|
+
sprites: Array<{
|
|
423
|
+
spriteIndex: number;
|
|
424
|
+
posX: number;
|
|
425
|
+
posY: number;
|
|
426
|
+
}>;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 0x11 - Bitmask: Renders a rectangular region with bitpacked presence mask
|
|
430
|
+
* Each bit represents presence (1) or absence (0) of the character at that position
|
|
431
|
+
* Ideal for: ore veins, destructible terrain, collision maps, fog of war, etc.
|
|
432
|
+
*/
|
|
433
|
+
interface BitmaskOrder extends NetworkOrder {
|
|
434
|
+
type: 0x11;
|
|
435
|
+
posX: number;
|
|
436
|
+
posY: number;
|
|
437
|
+
sizeX: number;
|
|
438
|
+
sizeY: number;
|
|
439
|
+
charCode: number;
|
|
440
|
+
bgColorCode: number;
|
|
441
|
+
fgColorCode: number;
|
|
442
|
+
override: boolean;
|
|
443
|
+
mask: Uint8Array;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* 0x13 - Clear: Fills entire layer with single character and colors
|
|
447
|
+
*/
|
|
448
|
+
interface ClearOrder extends NetworkOrder {
|
|
449
|
+
type: 0x13;
|
|
450
|
+
charCode: number;
|
|
451
|
+
bgColorCode: number;
|
|
452
|
+
fgColorCode: number;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* 0x14 - FillChar: Fills layer with repeating character pattern
|
|
456
|
+
*/
|
|
457
|
+
interface FillCharOrder extends NetworkOrder {
|
|
458
|
+
type: 0x14;
|
|
459
|
+
patternWidth: number;
|
|
460
|
+
patternHeight: number;
|
|
461
|
+
bgColorCode: number;
|
|
462
|
+
fgColorCode: number;
|
|
463
|
+
pattern: number[];
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* 0x15 - FillSprite: Fills layer with repeating unicolor sprite
|
|
467
|
+
*/
|
|
468
|
+
interface FillSpriteOrder extends NetworkOrder {
|
|
469
|
+
type: 0x15;
|
|
470
|
+
spriteIndex: number;
|
|
471
|
+
bgColorCode: number;
|
|
472
|
+
fgColorCode: number;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* 0x16 - FillSpriteMultiColor: Fills layer with repeating multicolor sprite
|
|
476
|
+
*/
|
|
477
|
+
interface FillSpriteMultiColorOrder extends NetworkOrder {
|
|
478
|
+
type: 0x16;
|
|
479
|
+
spriteIndex: number;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* 0x20 - TriggerSound: Triggers positional sound effect
|
|
483
|
+
*/
|
|
484
|
+
interface TriggerSoundOrder extends NetworkOrder {
|
|
485
|
+
type: 0x20;
|
|
486
|
+
posX: number;
|
|
487
|
+
posY: number;
|
|
488
|
+
soundId: number;
|
|
489
|
+
loop: boolean;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* 0x21 - TriggerGlobalSound: Triggers global (non-positional) sound
|
|
493
|
+
*/
|
|
494
|
+
interface TriggerGlobalSoundOrder extends NetworkOrder {
|
|
495
|
+
type: 0x21;
|
|
496
|
+
soundId: number;
|
|
497
|
+
loop: boolean;
|
|
498
|
+
}
|
|
499
|
+
type AnyNetworkOrder = CharOrder | TextOrder | TextMultilineOrder | SubFrameOrder | SubFrameMultiColorOrder | FullFrameOrder | FullFrameMultiColorOrder | SpriteOrder | SpriteMultiColorOrder | ColorMapOrder | ShapeOrder | DotCloudOrder | DotCloudMultiColorOrder | BitmaskOrder | SpriteCloudOrder | SpriteCloudMultiColorOrder | SpriteCloudVariedOrder | SpriteCloudVariedMultiColorOrder | ClearOrder | FillCharOrder | FillSpriteOrder | FillSpriteMultiColorOrder | TriggerSoundOrder | TriggerGlobalSoundOrder;
|
|
500
|
+
|
|
501
|
+
interface NetworkLayer {
|
|
502
|
+
id: number;
|
|
503
|
+
updateFlags: number;
|
|
504
|
+
zIndex: number;
|
|
505
|
+
originX: number;
|
|
506
|
+
originY: number;
|
|
507
|
+
width: number;
|
|
508
|
+
height: number;
|
|
509
|
+
orderCount: number;
|
|
510
|
+
orders: AnyNetworkOrder[];
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Update packet according to the new UTSP protocol
|
|
515
|
+
* Layers are at the User level, not under displays
|
|
516
|
+
*/
|
|
517
|
+
interface UpdatePacket {
|
|
518
|
+
/** Tick counter (8 bytes) */
|
|
519
|
+
tick: number;
|
|
520
|
+
/** Number of displays (2 bytes) */
|
|
521
|
+
displayCount: number;
|
|
522
|
+
/** List of displays with their origins */
|
|
523
|
+
displays: NetworkDisplay[];
|
|
524
|
+
/** Number of layers (2 bytes) */
|
|
525
|
+
layerCount: number;
|
|
526
|
+
/** List of layers (shared across all displays) */
|
|
527
|
+
layers: NetworkLayer[];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Represents a display (camera) in the virtual world
|
|
532
|
+
*
|
|
533
|
+
* ARCHITECTURE (new protocol):
|
|
534
|
+
* - Display = camera looking into the virtual world
|
|
535
|
+
* - LAYERS are NO LONGER in Display, they are at User level
|
|
536
|
+
* - Display only defines WHICH PART of the world we see (origin)
|
|
537
|
+
*/
|
|
538
|
+
declare class Display {
|
|
539
|
+
private id;
|
|
540
|
+
private origin;
|
|
541
|
+
private size;
|
|
542
|
+
private previousOrigin;
|
|
543
|
+
private previousSize;
|
|
544
|
+
private toDraw;
|
|
545
|
+
constructor(id?: number, sizeX?: number, sizeY?: number);
|
|
546
|
+
/**
|
|
547
|
+
* Gets the display ID (0-255)
|
|
548
|
+
*/
|
|
549
|
+
getId(): number;
|
|
550
|
+
/**
|
|
551
|
+
* Gets the origin position in the world
|
|
552
|
+
*/
|
|
553
|
+
getOrigin(): Vector2;
|
|
554
|
+
/**
|
|
555
|
+
* Sets the origin position in the world
|
|
556
|
+
*/
|
|
557
|
+
setOrigin(origin: Vector2): void;
|
|
558
|
+
/**
|
|
559
|
+
* Moves the origin in the world
|
|
560
|
+
*/
|
|
561
|
+
moveOrigin(deltaX: number, deltaY: number): void;
|
|
562
|
+
/**
|
|
563
|
+
* Checks if display origin has changed since last tick
|
|
564
|
+
* @internal - Used to calculate if update should be sent
|
|
565
|
+
*/
|
|
566
|
+
hasOriginChanged(): boolean;
|
|
567
|
+
/**
|
|
568
|
+
* Checks if display size has changed since last tick
|
|
569
|
+
* @internal - Used to calculate if update should be sent
|
|
570
|
+
*/
|
|
571
|
+
hasSizeChanged(): boolean;
|
|
572
|
+
/**
|
|
573
|
+
* Checks if display has changed (origin OR size)
|
|
574
|
+
* @internal
|
|
575
|
+
*/
|
|
576
|
+
hasChanged(): boolean;
|
|
577
|
+
/**
|
|
578
|
+
* Resets change tracking
|
|
579
|
+
* @internal - Called by Core.endTick() after sending updates
|
|
580
|
+
*/
|
|
581
|
+
resetChangeTracking(): void;
|
|
582
|
+
/**
|
|
583
|
+
* Gets the display size
|
|
584
|
+
*/
|
|
585
|
+
getSize(): Vector2;
|
|
586
|
+
/**
|
|
587
|
+
* Sets the display size
|
|
588
|
+
*/
|
|
589
|
+
setSize(size: Vector2): void;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
interface Cell {
|
|
593
|
+
charCode: number;
|
|
594
|
+
fgColorCode: number;
|
|
595
|
+
bgColorCode: number;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Optimized buffer for 65,536 cells with TypedArray
|
|
599
|
+
* Interleaved structure: [char0, fg0, bg0, char1, fg1, bg1, ...]
|
|
600
|
+
*
|
|
601
|
+
* Performance:
|
|
602
|
+
* - clear(): ~5-10μs (vs 826μs with object array)
|
|
603
|
+
* - Better cache locality
|
|
604
|
+
* - Less GC pressure
|
|
605
|
+
*/
|
|
606
|
+
declare class CellBuffer {
|
|
607
|
+
private data;
|
|
608
|
+
private size;
|
|
609
|
+
constructor(size?: number);
|
|
610
|
+
/**
|
|
611
|
+
* Optimized clear: fills with "skip" values
|
|
612
|
+
* - charCode = 0 (no character)
|
|
613
|
+
* - fgColorCode = 255 (COLOR_SKIP = transparent)
|
|
614
|
+
* - bgColorCode = 255 (COLOR_SKIP = transparent)
|
|
615
|
+
* Performance: ~5-10μs (native TypedArray)
|
|
616
|
+
*/
|
|
617
|
+
clear(): void;
|
|
618
|
+
/**
|
|
619
|
+
* Optimized clear with uniform color
|
|
620
|
+
* Faster than clear() when clearing to specific char/colors
|
|
621
|
+
* Useful for background layers with uniform color
|
|
622
|
+
*
|
|
623
|
+
* Performance: ~2-5μs (loop unrolling friendly)
|
|
624
|
+
*
|
|
625
|
+
* @param charCode - Character to fill (e.g., 0x20 for space)
|
|
626
|
+
* @param fgColorCode - Foreground color (0-255)
|
|
627
|
+
* @param bgColorCode - Background color (0-255)
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* // Clear to black background
|
|
631
|
+
* buffer.clearWithColor(0x20, 15, 0);
|
|
632
|
+
*/
|
|
633
|
+
clearWithColor(charCode: number, fgColorCode: number, bgColorCode: number): void;
|
|
634
|
+
/**
|
|
635
|
+
* Sets a cell at given index
|
|
636
|
+
*/
|
|
637
|
+
set(index: number, charCode: number, fgColorCode: number, bgColorCode: number): void;
|
|
638
|
+
/**
|
|
639
|
+
* Optimized batch fill for uniform char+colors (DotCloud, SpriteCloud)
|
|
640
|
+
* Writes only characters at multiple positions with uniform fg/bg colors
|
|
641
|
+
*
|
|
642
|
+
* Performance: 2-3x faster than individual set() calls for uniform colors
|
|
643
|
+
* Reduces memory writes by 66% (writes chars only, then batch-fills colors)
|
|
644
|
+
*
|
|
645
|
+
* @param indices - Array of cell indices to fill
|
|
646
|
+
* @param charCode - Character to write at all positions
|
|
647
|
+
* @param fgColorCode - Uniform foreground color
|
|
648
|
+
* @param bgColorCode - Uniform background color
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* // Rain drops (1,500 positions with same color)
|
|
652
|
+
* const indices = raindrops.map(d => d.y * width + d.x);
|
|
653
|
+
* buffer.fillCharsUniform(indices, 58, 20, 255); // ':' char, cyan, transparent
|
|
654
|
+
*/
|
|
655
|
+
fillCharsUniform(indices: number[], charCode: number, fgColorCode: number, bgColorCode: number): void;
|
|
656
|
+
/**
|
|
657
|
+
* Gets a cell at given index
|
|
658
|
+
* Returns a Cell object for compatibility
|
|
659
|
+
*/
|
|
660
|
+
get(index: number): Cell;
|
|
661
|
+
/**
|
|
662
|
+
* Sets only character at given index (keeps existing colors)
|
|
663
|
+
* Useful for operations that modify chars but preserve colors
|
|
664
|
+
*
|
|
665
|
+
* @param index - Cell index
|
|
666
|
+
* @param charCode - Character code to write
|
|
667
|
+
*/
|
|
668
|
+
setCharOnly(index: number, charCode: number): void;
|
|
669
|
+
/**
|
|
670
|
+
* Sets only colors at given index (keeps existing char)
|
|
671
|
+
* Useful for ColorMapOrder (updates colors, preserves chars)
|
|
672
|
+
*
|
|
673
|
+
* @param index - Cell index
|
|
674
|
+
* @param fgColorCode - Foreground color
|
|
675
|
+
* @param bgColorCode - Background color
|
|
676
|
+
*/
|
|
677
|
+
setColorsOnly(index: number, fgColorCode: number, bgColorCode: number): void;
|
|
678
|
+
/**
|
|
679
|
+
* Direct value access (faster than get())
|
|
680
|
+
* Note: These are called in hot loops, keep as inline as possible
|
|
681
|
+
*/
|
|
682
|
+
getCharCode(index: number): number;
|
|
683
|
+
getFgColorCode(index: number): number;
|
|
684
|
+
getBgColorCode(index: number): number;
|
|
685
|
+
/**
|
|
686
|
+
* Direct TypedArray access for batch operations
|
|
687
|
+
*/
|
|
688
|
+
getRawData(): Uint8Array;
|
|
689
|
+
/**
|
|
690
|
+
* Buffer size (number of cells)
|
|
691
|
+
*/
|
|
692
|
+
getSize(): number;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Optimized buffer to store only charcodes (unicolor sprites)
|
|
696
|
+
* Simple structure: [char0, char1, char2, ...]
|
|
697
|
+
*
|
|
698
|
+
* Performance:
|
|
699
|
+
* - 3x less memory than CellBuffer (1 byte vs 3 bytes per cell)
|
|
700
|
+
* - Ideal for unicolor sprites where colors are defined at render time
|
|
701
|
+
* - Cache-friendly with TypedArray
|
|
702
|
+
*/
|
|
703
|
+
declare class CharCodeBuffer {
|
|
704
|
+
private data;
|
|
705
|
+
private size;
|
|
706
|
+
constructor(size: number);
|
|
707
|
+
/**
|
|
708
|
+
* Optimized clear: fills with zeros (no character)
|
|
709
|
+
*/
|
|
710
|
+
clear(): void;
|
|
711
|
+
/**
|
|
712
|
+
* Sets a charcode at given index
|
|
713
|
+
*/
|
|
714
|
+
set(index: number, charCode: number): void;
|
|
715
|
+
/**
|
|
716
|
+
* Gets a charcode at given index
|
|
717
|
+
*/
|
|
718
|
+
get(index: number): number;
|
|
719
|
+
/**
|
|
720
|
+
* Direct TypedArray access for batch operations
|
|
721
|
+
*/
|
|
722
|
+
getRawData(): Uint8Array;
|
|
723
|
+
/**
|
|
724
|
+
* Buffer size (number of cells)
|
|
725
|
+
*/
|
|
726
|
+
getSize(): number;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Unicolor sprite - Stores only charcodes
|
|
731
|
+
* Colors (fg/bg) are defined at render time via SpriteOrder
|
|
732
|
+
*
|
|
733
|
+
* Used with LoadType.Sprite (0x02) and SpriteOrder (0x07)
|
|
734
|
+
*/
|
|
735
|
+
interface UnicolorSprite {
|
|
736
|
+
id: number;
|
|
737
|
+
sizeX: number;
|
|
738
|
+
sizeY: number;
|
|
739
|
+
data: CharCodeBuffer;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Multicolor sprite - Stores charcodes + fg/bg colors
|
|
743
|
+
* Each cell contains its own color set
|
|
744
|
+
*
|
|
745
|
+
* Used with LoadType.MulticolorSprite (0x03) and SpriteMultiColorOrder (0x08)
|
|
746
|
+
*/
|
|
747
|
+
interface MulticolorSprite {
|
|
748
|
+
id: number;
|
|
749
|
+
sizeX: number;
|
|
750
|
+
sizeY: number;
|
|
751
|
+
data: CellBuffer;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* UTSP Load Packet Types
|
|
756
|
+
* Based on UTSP Protocol v0.1 - Section 4: Load Section
|
|
757
|
+
*/
|
|
758
|
+
/**
|
|
759
|
+
* LoadType enumeration
|
|
760
|
+
*/
|
|
761
|
+
declare enum LoadType {
|
|
762
|
+
ColorPalette = 1,
|
|
763
|
+
Sprite = 2,
|
|
764
|
+
MulticolorSprite = 3,
|
|
765
|
+
BitmapFont = 4,// Formerly "Charset" - pixel-based fonts
|
|
766
|
+
Sound = 5,
|
|
767
|
+
WebFont = 6
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Color definition with RGBA+E values
|
|
771
|
+
*/
|
|
772
|
+
interface Color {
|
|
773
|
+
colorId: number;
|
|
774
|
+
r: number;
|
|
775
|
+
g: number;
|
|
776
|
+
b: number;
|
|
777
|
+
a: number;
|
|
778
|
+
e?: number;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Color Palette Load (LoadType 0x01)
|
|
782
|
+
* Loads a palette of RGBA+E colors
|
|
783
|
+
*/
|
|
784
|
+
interface ColorPaletteLoad {
|
|
785
|
+
loadType: LoadType.ColorPalette;
|
|
786
|
+
colors: Color[];
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Simple Sprite Load (LoadType 0x02)
|
|
790
|
+
* Each cell contains only a character code
|
|
791
|
+
*/
|
|
792
|
+
interface SpriteLoad {
|
|
793
|
+
loadType: LoadType.Sprite;
|
|
794
|
+
sprites: Array<{
|
|
795
|
+
spriteId: number;
|
|
796
|
+
sizeX: number;
|
|
797
|
+
sizeY: number;
|
|
798
|
+
data: number[];
|
|
799
|
+
}>;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Cell in a multicolor sprite
|
|
803
|
+
*/
|
|
804
|
+
interface MulticolorCell {
|
|
805
|
+
charCode: number;
|
|
806
|
+
fgColorId: number;
|
|
807
|
+
bgColorId: number;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Multicolor Sprite Load (LoadType 0x03)
|
|
811
|
+
* Each cell contains charcode + foreground color + background color
|
|
812
|
+
*/
|
|
813
|
+
interface MulticolorSpriteLoad {
|
|
814
|
+
loadType: LoadType.MulticolorSprite;
|
|
815
|
+
sprites: Array<{
|
|
816
|
+
spriteId: number;
|
|
817
|
+
sizeX: number;
|
|
818
|
+
sizeY: number;
|
|
819
|
+
data: MulticolorCell[];
|
|
820
|
+
}>;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* BitmapFont Load (LoadType 0x04)
|
|
824
|
+
* Custom character definitions (monochrome bitmaps)
|
|
825
|
+
* Formerly known as "Charset" - renamed to BitmapFont for clarity
|
|
826
|
+
*/
|
|
827
|
+
interface BitmapFontLoad {
|
|
828
|
+
loadType: LoadType.BitmapFont;
|
|
829
|
+
fontId: number;
|
|
830
|
+
width: number;
|
|
831
|
+
height: number;
|
|
832
|
+
cellWidth: number;
|
|
833
|
+
cellHeight: number;
|
|
834
|
+
characters: Array<{
|
|
835
|
+
charCode: number;
|
|
836
|
+
bitmap: Uint8Array;
|
|
837
|
+
}>;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* WebFont Load (LoadType 0x06)
|
|
841
|
+
* CSS-based font definitions for browser rendering
|
|
842
|
+
* Note: The default font is "Courier New" (monospace), but users can specify non-monospace fonts
|
|
843
|
+
*/
|
|
844
|
+
interface WebFontLoad {
|
|
845
|
+
loadType: LoadType.WebFont;
|
|
846
|
+
fontId: number;
|
|
847
|
+
fontFamily: string;
|
|
848
|
+
fontSize: number;
|
|
849
|
+
offsetX?: number;
|
|
850
|
+
offsetY?: number;
|
|
851
|
+
charSpacing?: number;
|
|
852
|
+
lineHeight?: number;
|
|
853
|
+
fontWeight?: string;
|
|
854
|
+
fontStyle?: string;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Sound Load (LoadType 0x05)
|
|
858
|
+
* MIDI sound data for audio playback
|
|
859
|
+
*/
|
|
860
|
+
interface SoundLoad {
|
|
861
|
+
loadType: LoadType.Sound;
|
|
862
|
+
sounds: Array<{
|
|
863
|
+
soundId: number;
|
|
864
|
+
midiData: Uint8Array;
|
|
865
|
+
}>;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Union type for all load types
|
|
869
|
+
*/
|
|
870
|
+
type AnyLoad = ColorPaletteLoad | SpriteLoad | MulticolorSpriteLoad | BitmapFontLoad | SoundLoad | WebFontLoad;
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Central registry to manage unicolor and multicolor sprites
|
|
874
|
+
*
|
|
875
|
+
* Sprites are loaded via LoadPacket and referenced by their ID
|
|
876
|
+
* in Orders (SpriteOrder, SpriteMultiColorOrder, etc.)
|
|
877
|
+
*
|
|
878
|
+
* Architecture:
|
|
879
|
+
* - Two separate registries for unicolor and multicolor
|
|
880
|
+
* - No possible collision between the two types
|
|
881
|
+
* - Memory optimization with CharCodeBuffer for unicolor
|
|
882
|
+
*/
|
|
883
|
+
declare class SpriteRegistry {
|
|
884
|
+
private unicolorSprites;
|
|
885
|
+
private multicolorSprites;
|
|
886
|
+
/**
|
|
887
|
+
* Loads unicolor sprites from a LoadPacket
|
|
888
|
+
* Converts network format to optimized internal format
|
|
889
|
+
*/
|
|
890
|
+
loadUnicolorSprites(loadData: SpriteLoad): void;
|
|
891
|
+
/**
|
|
892
|
+
* Loads multicolor sprites from a LoadPacket
|
|
893
|
+
* Converts network format to optimized internal format
|
|
894
|
+
*/
|
|
895
|
+
loadMulticolorSprites(loadData: MulticolorSpriteLoad): void;
|
|
896
|
+
/**
|
|
897
|
+
* Retrieves a unicolor sprite by its ID
|
|
898
|
+
*/
|
|
899
|
+
getUnicolorSprite(id: number): UnicolorSprite | undefined;
|
|
900
|
+
/**
|
|
901
|
+
* Retrieves a multicolor sprite by its ID
|
|
902
|
+
*/
|
|
903
|
+
getMulticolorSprite(id: number): MulticolorSprite | undefined;
|
|
904
|
+
/**
|
|
905
|
+
* Checks if a unicolor sprite exists
|
|
906
|
+
*/
|
|
907
|
+
hasUnicolorSprite(id: number): boolean;
|
|
908
|
+
/**
|
|
909
|
+
* Checks if a multicolor sprite exists
|
|
910
|
+
*/
|
|
911
|
+
hasMulticolorSprite(id: number): boolean;
|
|
912
|
+
/**
|
|
913
|
+
* Removes a unicolor sprite
|
|
914
|
+
*/
|
|
915
|
+
unloadUnicolorSprite(id: number): boolean;
|
|
916
|
+
/**
|
|
917
|
+
* Removes a multicolor sprite
|
|
918
|
+
*/
|
|
919
|
+
unloadMulticolorSprite(id: number): boolean;
|
|
920
|
+
/**
|
|
921
|
+
* Clears all unicolor sprites
|
|
922
|
+
*/
|
|
923
|
+
clearUnicolorSprites(): void;
|
|
924
|
+
/**
|
|
925
|
+
* Clears all multicolor sprites
|
|
926
|
+
*/
|
|
927
|
+
clearMulticolorSprites(): void;
|
|
928
|
+
/**
|
|
929
|
+
* Clears all sprites (unicolor and multicolor)
|
|
930
|
+
*/
|
|
931
|
+
clearAll(): void;
|
|
932
|
+
/**
|
|
933
|
+
* Number of loaded unicolor sprites
|
|
934
|
+
*/
|
|
935
|
+
getUnicolorSpriteCount(): number;
|
|
936
|
+
/**
|
|
937
|
+
* Number of loaded multicolor sprites
|
|
938
|
+
*/
|
|
939
|
+
getMulticolorSpriteCount(): number;
|
|
940
|
+
/**
|
|
941
|
+
* Total number of loaded sprites
|
|
942
|
+
*/
|
|
943
|
+
getTotalSpriteCount(): number;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
declare class Layer {
|
|
947
|
+
private id;
|
|
948
|
+
private origin;
|
|
949
|
+
private orders;
|
|
950
|
+
private zOrder;
|
|
951
|
+
private data;
|
|
952
|
+
private width;
|
|
953
|
+
private height;
|
|
954
|
+
private isStatic;
|
|
955
|
+
private spriteRegistry?;
|
|
956
|
+
private mode;
|
|
957
|
+
private previousOrigin;
|
|
958
|
+
private previousZOrder;
|
|
959
|
+
private enabled;
|
|
960
|
+
private useSetMode;
|
|
961
|
+
private needsCommit;
|
|
962
|
+
private static rasterizer;
|
|
963
|
+
constructor(origin: Vector2, zOrder: number, width: number, height: number, isStatic?: boolean);
|
|
964
|
+
/**
|
|
965
|
+
* Configures the layer's execution mode (called by User)
|
|
966
|
+
* @internal
|
|
967
|
+
*/
|
|
968
|
+
setMode(mode: CoreMode): void;
|
|
969
|
+
/**
|
|
970
|
+
* Injects the SpriteRegistry into the layer (called by Core)
|
|
971
|
+
* @internal
|
|
972
|
+
*/
|
|
973
|
+
setSpriteRegistry(registry: SpriteRegistry): void;
|
|
974
|
+
getOrders(): AnyNetworkOrder[];
|
|
975
|
+
/**
|
|
976
|
+
* Adds orders to the layer (incremental mode)
|
|
977
|
+
* Automatically rasterizes new orders in ADD mode
|
|
978
|
+
*/
|
|
979
|
+
addOrders(orders: AnyNetworkOrder[]): void;
|
|
980
|
+
/**
|
|
981
|
+
* Replaces all orders in the layer (reset mode)
|
|
982
|
+
* Automatically rasterizes all orders in SET mode
|
|
983
|
+
*/
|
|
984
|
+
setOrders(orders: AnyNetworkOrder[]): void;
|
|
985
|
+
/**
|
|
986
|
+
* Clears all orders and cleans the buffer
|
|
987
|
+
*/
|
|
988
|
+
clearOrders(): void;
|
|
989
|
+
getOrigin(): Vector2;
|
|
990
|
+
/**
|
|
991
|
+
* Updates the layer's origin and rasterizes if necessary
|
|
992
|
+
*
|
|
993
|
+
* In client mode, this method automatically rasterizes the layer
|
|
994
|
+
* to reflect the new position.
|
|
995
|
+
*
|
|
996
|
+
* @param origin - New layer origin
|
|
997
|
+
*/
|
|
998
|
+
setOrigin(origin: Vector2): void;
|
|
999
|
+
getZOrder(): number;
|
|
1000
|
+
/**
|
|
1001
|
+
* Updates the layer's z-order
|
|
1002
|
+
*
|
|
1003
|
+
* @param zOrder - New z-order
|
|
1004
|
+
*/
|
|
1005
|
+
setZOrder(zOrder: number): void;
|
|
1006
|
+
/**
|
|
1007
|
+
* Gets the layer's unique ID
|
|
1008
|
+
*
|
|
1009
|
+
* Used for client-side reconstruction when applying UpdatePackets.
|
|
1010
|
+
* The ID allows associating a NetworkLayer with its corresponding Layer.
|
|
1011
|
+
*
|
|
1012
|
+
* @returns Layer ID (0-65535)
|
|
1013
|
+
*/
|
|
1014
|
+
getId(): number;
|
|
1015
|
+
/**
|
|
1016
|
+
* Sets the layer's unique ID
|
|
1017
|
+
*
|
|
1018
|
+
* @internal - Used by User.applyUpdate() during reconstruction
|
|
1019
|
+
* @param id - Unique layer ID (0-65535)
|
|
1020
|
+
*/
|
|
1021
|
+
setId(id: number): void;
|
|
1022
|
+
getData(): CellBuffer;
|
|
1023
|
+
getWidth(): number;
|
|
1024
|
+
getHeight(): number;
|
|
1025
|
+
getCellAt(x: number, y: number): Cell | null;
|
|
1026
|
+
/**
|
|
1027
|
+
* Marks this layer as static or dynamic
|
|
1028
|
+
*
|
|
1029
|
+
* Static layer: Sent only once to client via reliable channel,
|
|
1030
|
+
* but continues to be rasterized client-side every frame.
|
|
1031
|
+
* Used for UI elements, backgrounds, elements that never change.
|
|
1032
|
+
*
|
|
1033
|
+
* Dynamic layer: Sent every tick via volatile channel.
|
|
1034
|
+
* Used for animated elements, players, projectiles, etc.
|
|
1035
|
+
*
|
|
1036
|
+
* @param isStatic - true for static, false for dynamic
|
|
1037
|
+
*/
|
|
1038
|
+
setStatic(isStatic: boolean): void;
|
|
1039
|
+
/**
|
|
1040
|
+
* Checks if this layer is static
|
|
1041
|
+
*/
|
|
1042
|
+
getStatic(): boolean;
|
|
1043
|
+
/**
|
|
1044
|
+
* Enables or disables the layer
|
|
1045
|
+
* A disabled layer will not be rendered by DisplayRasterizer
|
|
1046
|
+
*
|
|
1047
|
+
* @param enabled - true to enable, false to disable
|
|
1048
|
+
*/
|
|
1049
|
+
setEnabled(enabled: boolean): void;
|
|
1050
|
+
/**
|
|
1051
|
+
* Checks if layer is enabled
|
|
1052
|
+
*/
|
|
1053
|
+
isEnabled(): boolean;
|
|
1054
|
+
/**
|
|
1055
|
+
* Checks if layer origin changed since last tick
|
|
1056
|
+
* @internal - Used to calculate UpdateFlags
|
|
1057
|
+
*/
|
|
1058
|
+
hasOriginChanged(): boolean;
|
|
1059
|
+
/**
|
|
1060
|
+
* Checks if layer z-order changed since last tick
|
|
1061
|
+
* @internal - Used to calculate UpdateFlags
|
|
1062
|
+
*/
|
|
1063
|
+
hasZOrderChanged(): boolean;
|
|
1064
|
+
/**
|
|
1065
|
+
* Calculates UpdateFlags based on layer state and changes
|
|
1066
|
+
* @internal - Used by Core.endTick()
|
|
1067
|
+
* @returns Bitpacked flags (0x00 to 0x0F)
|
|
1068
|
+
*
|
|
1069
|
+
* Flag structure:
|
|
1070
|
+
* - Bit 0 (0x01): Layer Enabled (1=active, 0=disabled)
|
|
1071
|
+
* - Bit 1 (0x02): SET Mode (1=SET, 0=ADD)
|
|
1072
|
+
* - Bit 2 (0x04): Position Changed
|
|
1073
|
+
* - Bit 3 (0x08): Z-Order Changed
|
|
1074
|
+
*/
|
|
1075
|
+
calculateUpdateFlags(): number;
|
|
1076
|
+
/**
|
|
1077
|
+
* Resets change tracking after sending a tick
|
|
1078
|
+
* @internal - Used by Core.endTick()
|
|
1079
|
+
*/
|
|
1080
|
+
resetChangeTracking(): void;
|
|
1081
|
+
/**
|
|
1082
|
+
* Marks the layer as needing to be sent on next tick
|
|
1083
|
+
*
|
|
1084
|
+
* Used to optimize bandwidth by sending only modified layers.
|
|
1085
|
+
*
|
|
1086
|
+
* @example
|
|
1087
|
+
* ```typescript
|
|
1088
|
+
* layer.addOrders([...]);
|
|
1089
|
+
* layer.commit(); // Layer will be sent on next tick
|
|
1090
|
+
* ```
|
|
1091
|
+
*/
|
|
1092
|
+
commit(): void;
|
|
1093
|
+
/**
|
|
1094
|
+
* Checks if layer needs to be sent
|
|
1095
|
+
* @internal - Used by Core.endTickSplit()
|
|
1096
|
+
*/
|
|
1097
|
+
getNeedsCommit(): boolean;
|
|
1098
|
+
/**
|
|
1099
|
+
* Resets commit flag after sending
|
|
1100
|
+
* @internal - Used by Core.endTickSplit()
|
|
1101
|
+
*/
|
|
1102
|
+
resetCommit(): void;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* InputBindingRegistry - Input bindings registry
|
|
1107
|
+
*
|
|
1108
|
+
* Allows the server to define available axes and buttons,
|
|
1109
|
+
* and send them to the client via a JSON LoadPacket.
|
|
1110
|
+
*
|
|
1111
|
+
* Architecture:
|
|
1112
|
+
* 1. Server defines bindings (bindingId ↔ name)
|
|
1113
|
+
* 2. Server generates a JSON LoadPacket
|
|
1114
|
+
* 3. Client receives LoadPacket and configures its mappings
|
|
1115
|
+
* 4. Client sends back compressed inputs (bindingId + value)
|
|
1116
|
+
* 5. Server decodes with registry (bindingId → name → setAxis/setButton)
|
|
1117
|
+
*/
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Input bindings registry
|
|
1121
|
+
*
|
|
1122
|
+
* Allows to:
|
|
1123
|
+
* - Define axes and buttons (bindingId → name)
|
|
1124
|
+
* - Generate a JSON LoadPacket to send to client
|
|
1125
|
+
* - Decode compressed inputs received from client (future)
|
|
1126
|
+
*/
|
|
1127
|
+
declare class InputBindingRegistry {
|
|
1128
|
+
private axes;
|
|
1129
|
+
private buttons;
|
|
1130
|
+
private axisNameToId;
|
|
1131
|
+
private buttonNameToId;
|
|
1132
|
+
private version;
|
|
1133
|
+
/**
|
|
1134
|
+
* Defines an axis binding
|
|
1135
|
+
*
|
|
1136
|
+
* @param bindingId - Unique axis ID (0-255)
|
|
1137
|
+
* @param name - Axis name (e.g., "MoveHorizontal", "CameraX")
|
|
1138
|
+
* @param sources - Physical sources (keyboard, gamepad, etc.)
|
|
1139
|
+
* @param min - Minimum axis value (default: -1.0)
|
|
1140
|
+
* @param max - Maximum axis value (default: +1.0)
|
|
1141
|
+
* @param defaultValue - Default axis value (default: 0.0)
|
|
1142
|
+
* @throws Error if bindingId or name already exists
|
|
1143
|
+
*
|
|
1144
|
+
* @example
|
|
1145
|
+
* ```typescript
|
|
1146
|
+
* import { InputDeviceType, KeyboardInput, GamepadInput } from '@utsp/types';
|
|
1147
|
+
*
|
|
1148
|
+
* registry.defineAxis(0, "MoveHorizontal", [
|
|
1149
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, negativeKey: KeyboardInput.ArrowLeft, positiveKey: KeyboardInput.ArrowRight },
|
|
1150
|
+
* { sourceId: 1, type: InputDeviceType.Gamepad, gamepadIndex: 0, axis: GamepadInput.LeftStickX }
|
|
1151
|
+
* ], -1.0, 1.0, 0.0);
|
|
1152
|
+
* ```
|
|
1153
|
+
*/
|
|
1154
|
+
defineAxis(bindingId: number, name: string, sources?: AxisSource[], min?: number, max?: number, defaultValue?: number): void;
|
|
1155
|
+
/**
|
|
1156
|
+
* Defines a button binding
|
|
1157
|
+
*
|
|
1158
|
+
* @param bindingId - Unique button ID (0-255)
|
|
1159
|
+
* @param name - Button name (e.g., "Jump", "Attack")
|
|
1160
|
+
* @param sources - Physical sources (keyboard, gamepad, mouse, touch)
|
|
1161
|
+
* @param defaultValue - Default button value (default: false)
|
|
1162
|
+
* @throws Error if bindingId or name already exists
|
|
1163
|
+
*
|
|
1164
|
+
* @example
|
|
1165
|
+
* ```typescript
|
|
1166
|
+
* import { InputDeviceType, KeyboardInput, GamepadInput } from '@utsp/types';
|
|
1167
|
+
*
|
|
1168
|
+
* registry.defineButton(0, "Jump", [
|
|
1169
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, key: KeyboardInput.Space },
|
|
1170
|
+
* { sourceId: 1, type: InputDeviceType.Gamepad, gamepadIndex: 0, button: GamepadInput.A }
|
|
1171
|
+
* ], false);
|
|
1172
|
+
* ```
|
|
1173
|
+
*/
|
|
1174
|
+
defineButton(bindingId: number, name: string, sources?: ButtonSource[], defaultValue?: boolean): void;
|
|
1175
|
+
/**
|
|
1176
|
+
* Evaluates an axis by summing all its sources
|
|
1177
|
+
*
|
|
1178
|
+
* This method takes raw values from each source (received from client)
|
|
1179
|
+
* and sums them according to the following logic:
|
|
1180
|
+
* 1. For each source: apply deadzone, scale, invert, sensitivity
|
|
1181
|
+
* 2. Sum all values
|
|
1182
|
+
* 3. Clamp between min and max
|
|
1183
|
+
*
|
|
1184
|
+
* Note: Raw source values are provided in sourceValues (Map<sourceId, value>)
|
|
1185
|
+
*
|
|
1186
|
+
* @param bindingId - Axis binding ID
|
|
1187
|
+
* @param sourceValues - Map of raw source values (sourceId → value)
|
|
1188
|
+
* @returns Final axis value (clamped), or defaultValue if binding not found
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* ```typescript
|
|
1192
|
+
* // Client sends: { sourceId: 0, value: -1.0 }, { sourceId: 1, value: 0.5 }
|
|
1193
|
+
* const sourceValues = new Map([[0, -1.0], [1, 0.5]]);
|
|
1194
|
+
* const axisValue = registry.evaluateAxis(0, sourceValues);
|
|
1195
|
+
* // Result: -1.0 + 0.5 = -0.5 (clamped between min and max)
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
evaluateAxis(bindingId: number, sourceValues: Map<number, number>): number;
|
|
1199
|
+
/**
|
|
1200
|
+
* Evaluates a button with OR logic on all its sources
|
|
1201
|
+
*
|
|
1202
|
+
* A button is considered pressed if AT LEAST ONE source is pressed.
|
|
1203
|
+
*
|
|
1204
|
+
* @param bindingId - Button binding ID
|
|
1205
|
+
* @param sourceValues - Map of source states (sourceId → pressed)
|
|
1206
|
+
* @returns true if at least one source is pressed, false otherwise
|
|
1207
|
+
*
|
|
1208
|
+
* @example
|
|
1209
|
+
* ```typescript
|
|
1210
|
+
* // Client sends: { sourceId: 0, pressed: false }, { sourceId: 1, pressed: true }
|
|
1211
|
+
* const sourceValues = new Map([[0, false], [1, true]]);
|
|
1212
|
+
* const buttonPressed = registry.evaluateButton(0, sourceValues);
|
|
1213
|
+
* // Result: true (because at least one source is pressed)
|
|
1214
|
+
* ```
|
|
1215
|
+
*/
|
|
1216
|
+
evaluateButton(bindingId: number, sourceValues: Map<number, boolean>): boolean;
|
|
1217
|
+
/**
|
|
1218
|
+
* Generates a LoadPacket JSON containing all bindings
|
|
1219
|
+
*
|
|
1220
|
+
* This packet will be sent to the client via the Load channel to indicate
|
|
1221
|
+
* which axes and buttons it should capture and send back.
|
|
1222
|
+
*
|
|
1223
|
+
* JSON format (not binary for now as sent rarely)
|
|
1224
|
+
*
|
|
1225
|
+
* @returns LoadPacket JSON as string
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```typescript
|
|
1229
|
+
* const packet = registry.toLoadPacket();
|
|
1230
|
+
* websocket.send(packet); // Send to client
|
|
1231
|
+
* ```
|
|
1232
|
+
*/
|
|
1233
|
+
toLoadPacket(): string;
|
|
1234
|
+
/**
|
|
1235
|
+
* Generates a LoadPacket JSON as object
|
|
1236
|
+
* (useful for inspection or tests)
|
|
1237
|
+
*
|
|
1238
|
+
* @returns LoadPacket as object
|
|
1239
|
+
*/
|
|
1240
|
+
toLoadPacketObject(): InputBindingLoadPacket;
|
|
1241
|
+
/**
|
|
1242
|
+
* Retrieves an axis bindingId from its name
|
|
1243
|
+
*
|
|
1244
|
+
* @param name - Axis name
|
|
1245
|
+
* @returns bindingId or null if not found
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* ```typescript
|
|
1249
|
+
* const id = registry.getAxisBindingId("MoveHorizontal");
|
|
1250
|
+
* if (id !== null) {
|
|
1251
|
+
* console.log(`MoveHorizontal has bindingId ${id}`);
|
|
1252
|
+
* }
|
|
1253
|
+
* ```
|
|
1254
|
+
*/
|
|
1255
|
+
getAxisBindingId(name: string): number | null;
|
|
1256
|
+
/**
|
|
1257
|
+
* Retrieves a button bindingId from its name
|
|
1258
|
+
*
|
|
1259
|
+
* @param name - Button name
|
|
1260
|
+
* @returns bindingId or null if not found
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```typescript
|
|
1264
|
+
* const id = registry.getButtonBindingId("Jump");
|
|
1265
|
+
* if (id !== null) {
|
|
1266
|
+
* console.log(`Jump has bindingId ${id}`);
|
|
1267
|
+
* }
|
|
1268
|
+
* ```
|
|
1269
|
+
*/
|
|
1270
|
+
getButtonBindingId(name: string): number | null;
|
|
1271
|
+
/**
|
|
1272
|
+
* Retrieves an axis name from its bindingId
|
|
1273
|
+
*
|
|
1274
|
+
* @param bindingId - Binding ID
|
|
1275
|
+
* @returns name or null if not found
|
|
1276
|
+
*
|
|
1277
|
+
* @example
|
|
1278
|
+
* ```typescript
|
|
1279
|
+
* const name = registry.getAxisName(0);
|
|
1280
|
+
* console.log(name); // "MoveHorizontal"
|
|
1281
|
+
* ```
|
|
1282
|
+
*/
|
|
1283
|
+
getAxisName(bindingId: number): string | null;
|
|
1284
|
+
/**
|
|
1285
|
+
* Retrieves a button name from its bindingId
|
|
1286
|
+
*
|
|
1287
|
+
* @param bindingId - Binding ID
|
|
1288
|
+
* @returns name or null if not found
|
|
1289
|
+
*
|
|
1290
|
+
* @example
|
|
1291
|
+
* ```typescript
|
|
1292
|
+
* const name = registry.getButtonName(0);
|
|
1293
|
+
* console.log(name); // "Jump"
|
|
1294
|
+
* ```
|
|
1295
|
+
*/
|
|
1296
|
+
getButtonName(bindingId: number): string | null;
|
|
1297
|
+
/**
|
|
1298
|
+
* Retrieves a complete axis binding
|
|
1299
|
+
*
|
|
1300
|
+
* @param bindingId - Binding ID
|
|
1301
|
+
* @returns binding or null if not found
|
|
1302
|
+
*/
|
|
1303
|
+
getAxisBinding(bindingId: number): AxisBinding | null;
|
|
1304
|
+
/**
|
|
1305
|
+
* Retrieves a complete button binding
|
|
1306
|
+
*
|
|
1307
|
+
* @param bindingId - Binding ID
|
|
1308
|
+
* @returns binding or null if not found
|
|
1309
|
+
*/
|
|
1310
|
+
getButtonBinding(bindingId: number): ButtonBinding | null;
|
|
1311
|
+
/**
|
|
1312
|
+
* Checks if an axis is defined
|
|
1313
|
+
*
|
|
1314
|
+
* @param bindingId - Binding ID
|
|
1315
|
+
* @returns true if defined
|
|
1316
|
+
*/
|
|
1317
|
+
hasAxis(bindingId: number): boolean;
|
|
1318
|
+
/**
|
|
1319
|
+
* Checks if a button is defined
|
|
1320
|
+
*
|
|
1321
|
+
* @param bindingId - Binding ID
|
|
1322
|
+
* @returns true if defined
|
|
1323
|
+
*/
|
|
1324
|
+
hasButton(bindingId: number): boolean;
|
|
1325
|
+
/**
|
|
1326
|
+
* Counts the number of defined axes
|
|
1327
|
+
*
|
|
1328
|
+
* @returns number of axes
|
|
1329
|
+
*/
|
|
1330
|
+
getAxisCount(): number;
|
|
1331
|
+
/**
|
|
1332
|
+
* Counts the number of defined buttons
|
|
1333
|
+
*
|
|
1334
|
+
* @returns number of buttons
|
|
1335
|
+
*/
|
|
1336
|
+
getButtonCount(): number;
|
|
1337
|
+
/**
|
|
1338
|
+
* Retrieves all axes
|
|
1339
|
+
*
|
|
1340
|
+
* @returns array of all axis bindings
|
|
1341
|
+
*/
|
|
1342
|
+
getAllAxes(): AxisBinding[];
|
|
1343
|
+
/**
|
|
1344
|
+
* Retrieves all buttons
|
|
1345
|
+
*
|
|
1346
|
+
* @returns array of all button bindings
|
|
1347
|
+
*/
|
|
1348
|
+
getAllButtons(): ButtonBinding[];
|
|
1349
|
+
/**
|
|
1350
|
+
* Retrieves the current binding version
|
|
1351
|
+
*
|
|
1352
|
+
* @returns version (incremented with each modification)
|
|
1353
|
+
*/
|
|
1354
|
+
getVersion(): number;
|
|
1355
|
+
/**
|
|
1356
|
+
* Removes an axis
|
|
1357
|
+
*
|
|
1358
|
+
* @param bindingId - Binding ID to remove
|
|
1359
|
+
* @returns true if removed, false if not found
|
|
1360
|
+
*/
|
|
1361
|
+
removeAxis(bindingId: number): boolean;
|
|
1362
|
+
/**
|
|
1363
|
+
* Removes a button
|
|
1364
|
+
*
|
|
1365
|
+
* @param bindingId - Binding ID to remove
|
|
1366
|
+
* @returns true if removed, false if not found
|
|
1367
|
+
*/
|
|
1368
|
+
removeButton(bindingId: number): boolean;
|
|
1369
|
+
/**
|
|
1370
|
+
* Removes all axes
|
|
1371
|
+
*/
|
|
1372
|
+
clearAxes(): void;
|
|
1373
|
+
/**
|
|
1374
|
+
* Removes all buttons
|
|
1375
|
+
*/
|
|
1376
|
+
clearButtons(): void;
|
|
1377
|
+
/**
|
|
1378
|
+
* Completely resets the registry
|
|
1379
|
+
*/
|
|
1380
|
+
clear(): void;
|
|
1381
|
+
/**
|
|
1382
|
+
* Displays a summary of bindings (for debug)
|
|
1383
|
+
*
|
|
1384
|
+
* @returns formatted string
|
|
1385
|
+
*/
|
|
1386
|
+
toString(): string;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/**
|
|
1390
|
+
* Per-user performance statistics
|
|
1391
|
+
* Collects user-specific metrics
|
|
1392
|
+
*/
|
|
1393
|
+
interface UserTickStats {
|
|
1394
|
+
userId: string;
|
|
1395
|
+
userName: string;
|
|
1396
|
+
tick: number;
|
|
1397
|
+
timestamp: number;
|
|
1398
|
+
displayCount: number;
|
|
1399
|
+
totalDisplayArea: number;
|
|
1400
|
+
totalLayers: number;
|
|
1401
|
+
visibleLayers: number;
|
|
1402
|
+
staticLayers: number;
|
|
1403
|
+
dynamicLayers: number;
|
|
1404
|
+
totalOrders: number;
|
|
1405
|
+
ordersByLayer: Map<number, number>;
|
|
1406
|
+
staticPacketSize: number;
|
|
1407
|
+
dynamicPacketSize: number;
|
|
1408
|
+
totalPacketSize: number;
|
|
1409
|
+
hasInput: boolean;
|
|
1410
|
+
axisCount: number;
|
|
1411
|
+
buttonCount: number;
|
|
1412
|
+
}
|
|
1413
|
+
declare class UserStats {
|
|
1414
|
+
private enabled;
|
|
1415
|
+
private currentStats;
|
|
1416
|
+
private _userId;
|
|
1417
|
+
private _userName;
|
|
1418
|
+
constructor(userId: string, userName: string);
|
|
1419
|
+
/**
|
|
1420
|
+
* Enables or disables statistics collection
|
|
1421
|
+
*/
|
|
1422
|
+
setEnabled(enabled: boolean): void;
|
|
1423
|
+
isEnabled(): boolean;
|
|
1424
|
+
/** User ID */
|
|
1425
|
+
get userId(): string;
|
|
1426
|
+
/** User name */
|
|
1427
|
+
get userName(): string;
|
|
1428
|
+
/** Current tick number */
|
|
1429
|
+
get tick(): number;
|
|
1430
|
+
/** Current tick timestamp */
|
|
1431
|
+
get timestamp(): number;
|
|
1432
|
+
/** Number of displays */
|
|
1433
|
+
get displayCount(): number;
|
|
1434
|
+
/** Total display surface area (width × height) */
|
|
1435
|
+
get totalDisplayArea(): number;
|
|
1436
|
+
/** Total number of layers */
|
|
1437
|
+
get totalLayers(): number;
|
|
1438
|
+
/** Visible layers in displays */
|
|
1439
|
+
get visibleLayers(): number;
|
|
1440
|
+
/** Static layers */
|
|
1441
|
+
get staticLayers(): number;
|
|
1442
|
+
/** Dynamic layers */
|
|
1443
|
+
get dynamicLayers(): number;
|
|
1444
|
+
/** Total orders for this user */
|
|
1445
|
+
get totalOrders(): number;
|
|
1446
|
+
/** Orders par layer ID */
|
|
1447
|
+
get ordersByLayer(): Map<number, number>;
|
|
1448
|
+
/** Taille du packet statique (octets) */
|
|
1449
|
+
get staticPacketSize(): number;
|
|
1450
|
+
/** Taille du packet dynamique (octets) */
|
|
1451
|
+
get dynamicPacketSize(): number;
|
|
1452
|
+
/** Taille totale des packets (static + dynamic) */
|
|
1453
|
+
get totalPacketSize(): number;
|
|
1454
|
+
/** Estimated size after gzip compression (25% of original size) */
|
|
1455
|
+
get compressedPacketSize(): number;
|
|
1456
|
+
/** If user sent input this tick */
|
|
1457
|
+
get hasInput(): boolean;
|
|
1458
|
+
/** Number of bound axes */
|
|
1459
|
+
get axisCount(): number;
|
|
1460
|
+
/** Number of bound buttons */
|
|
1461
|
+
get buttonCount(): number;
|
|
1462
|
+
/**
|
|
1463
|
+
* @internal
|
|
1464
|
+
* Starts collection for a new tick
|
|
1465
|
+
*/
|
|
1466
|
+
startTick(tickNumber: number): void;
|
|
1467
|
+
/**
|
|
1468
|
+
* @internal
|
|
1469
|
+
* Records display information
|
|
1470
|
+
*/
|
|
1471
|
+
recordDisplays(displayCount: number, totalArea: number): void;
|
|
1472
|
+
/**
|
|
1473
|
+
* @internal
|
|
1474
|
+
* Enregistre les informations des layers
|
|
1475
|
+
*/
|
|
1476
|
+
recordLayers(total: number, visible: number, staticCount: number, dynamicCount: number): void;
|
|
1477
|
+
/**
|
|
1478
|
+
* @internal
|
|
1479
|
+
* Enregistre les orders d'un layer
|
|
1480
|
+
*/
|
|
1481
|
+
recordLayerOrders(layerId: number, orderCount: number): void;
|
|
1482
|
+
/**
|
|
1483
|
+
* @internal
|
|
1484
|
+
* Records network packet sizes
|
|
1485
|
+
*/
|
|
1486
|
+
recordPacketSizes(staticSize: number, dynamicSize: number): void;
|
|
1487
|
+
/**
|
|
1488
|
+
* @internal
|
|
1489
|
+
* Records input information
|
|
1490
|
+
*/
|
|
1491
|
+
recordInput(hasInput: boolean, axisCount: number, buttonCount: number): void;
|
|
1492
|
+
/**
|
|
1493
|
+
* @internal
|
|
1494
|
+
* Finalizes current tick stats
|
|
1495
|
+
*/
|
|
1496
|
+
endTick(): void;
|
|
1497
|
+
/**
|
|
1498
|
+
* Resets statistics
|
|
1499
|
+
*/
|
|
1500
|
+
reset(): void;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Represents a connected user with their displays and layers
|
|
1505
|
+
*
|
|
1506
|
+
* ARCHITECTURE (new protocol):
|
|
1507
|
+
* - LAYERS are at the USER level (shared across all displays)
|
|
1508
|
+
* - DISPLAYS are origins (cameras) that look into the world
|
|
1509
|
+
* - Each display can see the same layers (if within its origin)
|
|
1510
|
+
*
|
|
1511
|
+
* @template TData - Application-specific data type (default: Record<string, any>)
|
|
1512
|
+
*/
|
|
1513
|
+
declare class User<TData = Record<string, any>> {
|
|
1514
|
+
id: string;
|
|
1515
|
+
name: string;
|
|
1516
|
+
private displays;
|
|
1517
|
+
private layers;
|
|
1518
|
+
private spriteRegistry;
|
|
1519
|
+
private mode;
|
|
1520
|
+
private axes;
|
|
1521
|
+
private buttons;
|
|
1522
|
+
private textInputs;
|
|
1523
|
+
private mouseX;
|
|
1524
|
+
private mouseY;
|
|
1525
|
+
private mouseOver;
|
|
1526
|
+
private mouseDisplayId;
|
|
1527
|
+
private touchPositions;
|
|
1528
|
+
private activeTouchId;
|
|
1529
|
+
private inputBindings;
|
|
1530
|
+
private stats;
|
|
1531
|
+
/**
|
|
1532
|
+
* Application-specific data storage
|
|
1533
|
+
* Use this to store game state, player data, or any custom information
|
|
1534
|
+
*/
|
|
1535
|
+
data: TData;
|
|
1536
|
+
constructor(id: string, name: string, mode: CoreMode);
|
|
1537
|
+
/**
|
|
1538
|
+
* Injects SpriteRegistry into the user (called by Core)
|
|
1539
|
+
* @internal
|
|
1540
|
+
*/
|
|
1541
|
+
setSpriteRegistry(registry: SpriteRegistry): void;
|
|
1542
|
+
getDisplays(): Display[];
|
|
1543
|
+
/**
|
|
1544
|
+
* Adds a display to the user
|
|
1545
|
+
*
|
|
1546
|
+
* @param display - The display to add
|
|
1547
|
+
*/
|
|
1548
|
+
addDisplay(display: Display): void;
|
|
1549
|
+
/**
|
|
1550
|
+
* Removes a display from the user
|
|
1551
|
+
*
|
|
1552
|
+
* @param display - The display to remove
|
|
1553
|
+
* @returns true if display was removed, false otherwise
|
|
1554
|
+
*/
|
|
1555
|
+
removeDisplay(display: Display): boolean;
|
|
1556
|
+
/**
|
|
1557
|
+
* Removes all displays from the user
|
|
1558
|
+
*/
|
|
1559
|
+
clearDisplays(): void;
|
|
1560
|
+
getLayers(): Layer[];
|
|
1561
|
+
/**
|
|
1562
|
+
* Adds a layer to the user
|
|
1563
|
+
* Layers are shared across all displays
|
|
1564
|
+
*
|
|
1565
|
+
* @param layer - The layer to add
|
|
1566
|
+
*/
|
|
1567
|
+
addLayer(layer: Layer): void;
|
|
1568
|
+
/**
|
|
1569
|
+
* Removes a layer from the user
|
|
1570
|
+
*
|
|
1571
|
+
* @param layer - The layer to remove
|
|
1572
|
+
* @returns true if layer was removed, false otherwise
|
|
1573
|
+
*/
|
|
1574
|
+
removeLayer(layer: Layer): boolean;
|
|
1575
|
+
/**
|
|
1576
|
+
* Removes all layers from the user
|
|
1577
|
+
*/
|
|
1578
|
+
clearLayers(): void;
|
|
1579
|
+
/**
|
|
1580
|
+
* Updates mouse position (called by client)
|
|
1581
|
+
*
|
|
1582
|
+
* @param x - X position (0-255)
|
|
1583
|
+
* @param y - Y position (0-255)
|
|
1584
|
+
* @param over - Is mouse over the display?
|
|
1585
|
+
*
|
|
1586
|
+
* @example
|
|
1587
|
+
* ```typescript
|
|
1588
|
+
* user.setMousePosition(128, 64, true);
|
|
1589
|
+
* ```
|
|
1590
|
+
*/
|
|
1591
|
+
setMousePosition(x: number, y: number, over?: boolean): void;
|
|
1592
|
+
/**
|
|
1593
|
+
* Sets the position of a touch (multi-touch support)
|
|
1594
|
+
*
|
|
1595
|
+
* @param touchId - Touch ID (0-9)
|
|
1596
|
+
* @param x - X position in display (0-255)
|
|
1597
|
+
* @param y - Y position in display (0-255)
|
|
1598
|
+
* @param over - If touch is active (true) or released (false)
|
|
1599
|
+
* @param displayId - ID of concerned display (0-255)
|
|
1600
|
+
*
|
|
1601
|
+
* @example
|
|
1602
|
+
* ```typescript
|
|
1603
|
+
* // Touch ID 0 at position (128, 64)
|
|
1604
|
+
* user.setTouchPosition(0, 128, 64, true, 0);
|
|
1605
|
+
* ```
|
|
1606
|
+
*/
|
|
1607
|
+
setTouchPosition(touchId: number, x: number, y: number, over?: boolean, displayId?: number): void;
|
|
1608
|
+
/**
|
|
1609
|
+
* Sets the value of a virtual axis
|
|
1610
|
+
*
|
|
1611
|
+
* Axes are floating point values between -1.0 and +1.0, typically used for:
|
|
1612
|
+
* - Movement (Horizontal, Vertical)
|
|
1613
|
+
* - Camera rotation (CameraX, CameraY)
|
|
1614
|
+
* - Analog controls (Throttle, Steering)
|
|
1615
|
+
*
|
|
1616
|
+
* Axis name is free-form and defined by the application.
|
|
1617
|
+
* Physical mapping (keyboard, gamepad, etc.) is handled by the client.
|
|
1618
|
+
*
|
|
1619
|
+
* @param axisName - Axis name (e.g., "Horizontal", "Vertical", "CameraX")
|
|
1620
|
+
* @param value - Axis value (-1.0 to +1.0)
|
|
1621
|
+
*
|
|
1622
|
+
* @example
|
|
1623
|
+
* ```typescript
|
|
1624
|
+
* // Client side: map keys to axes
|
|
1625
|
+
* user.setAxis("Horizontal", keyboard.arrowLeft ? -1.0 : keyboard.arrowRight ? 1.0 : 0.0);
|
|
1626
|
+
* user.setAxis("Vertical", keyboard.arrowUp ? -1.0 : keyboard.arrowDown ? 1.0 : 0.0);
|
|
1627
|
+
* user.setAxis("CameraX", gamepad.rightStickX); // -1.0 to +1.0
|
|
1628
|
+
* ```
|
|
1629
|
+
*/
|
|
1630
|
+
setAxis(axisName: string, value: number): void;
|
|
1631
|
+
/**
|
|
1632
|
+
* Gets the value of a virtual axis
|
|
1633
|
+
*
|
|
1634
|
+
* @param axisName - Axis name (e.g., "Horizontal", "Vertical")
|
|
1635
|
+
* @returns Axis value (-1.0 to +1.0), or 0.0 if axis doesn't exist
|
|
1636
|
+
*
|
|
1637
|
+
* @example
|
|
1638
|
+
* ```typescript
|
|
1639
|
+
* // Server side: use axes for game logic
|
|
1640
|
+
* const moveX = user.getAxis("Horizontal");
|
|
1641
|
+
* const moveY = user.getAxis("Vertical");
|
|
1642
|
+
* player.move(moveX, moveY);
|
|
1643
|
+
* ```
|
|
1644
|
+
*/
|
|
1645
|
+
getAxis(axisName: string): number;
|
|
1646
|
+
/**
|
|
1647
|
+
* Sets the state of a virtual button
|
|
1648
|
+
*
|
|
1649
|
+
* Buttons are boolean values used for actions:
|
|
1650
|
+
* - Point actions (Jump, Fire, Interact)
|
|
1651
|
+
* - Continuous states (Run, Crouch, Aim)
|
|
1652
|
+
*
|
|
1653
|
+
* Button name is free-form and defined by the application.
|
|
1654
|
+
* Physical mapping (keyboard, gamepad, etc.) is handled by the client.
|
|
1655
|
+
*
|
|
1656
|
+
* @param buttonName - Button name (e.g., "Jump", "Fire", "Inventory")
|
|
1657
|
+
* @param pressed - Button state (true = pressed, false = released)
|
|
1658
|
+
*
|
|
1659
|
+
* @example
|
|
1660
|
+
* ```typescript
|
|
1661
|
+
* // Client side: map keys to buttons
|
|
1662
|
+
* user.setButton("Jump", keyboard.space || mouse.leftClick);
|
|
1663
|
+
* user.setButton("Fire", mouse.rightClick);
|
|
1664
|
+
* user.setButton("Inventory", keyboard.i);
|
|
1665
|
+
* user.setButton("Sprint", keyboard.shift);
|
|
1666
|
+
* ```
|
|
1667
|
+
*/
|
|
1668
|
+
setButton(buttonName: string, pressed: boolean): void;
|
|
1669
|
+
/**
|
|
1670
|
+
* Checks if a virtual button is pressed
|
|
1671
|
+
*
|
|
1672
|
+
* @param buttonName - Button name (e.g., "Jump", "Fire")
|
|
1673
|
+
* @returns true if button is pressed, false otherwise
|
|
1674
|
+
*
|
|
1675
|
+
* @example
|
|
1676
|
+
* ```typescript
|
|
1677
|
+
* // Server side: use buttons for game logic
|
|
1678
|
+
* if (user.getButton("Jump")) {
|
|
1679
|
+
* player.jump();
|
|
1680
|
+
* }
|
|
1681
|
+
*
|
|
1682
|
+
* if (user.getButton("Fire")) {
|
|
1683
|
+
* player.shoot();
|
|
1684
|
+
* }
|
|
1685
|
+
*
|
|
1686
|
+
* if (user.getButton("Sprint")) {
|
|
1687
|
+
* player.speed = 2.0;
|
|
1688
|
+
* } else {
|
|
1689
|
+
* player.speed = 1.0;
|
|
1690
|
+
* }
|
|
1691
|
+
* ```
|
|
1692
|
+
*/
|
|
1693
|
+
getButton(buttonName: string): boolean;
|
|
1694
|
+
/**
|
|
1695
|
+
* Checks if a virtual button was just pressed this frame
|
|
1696
|
+
*
|
|
1697
|
+
* @param buttonName - Button name (e.g., "Jump", "Fire")
|
|
1698
|
+
* @returns true if button just transitioned from false→true
|
|
1699
|
+
*
|
|
1700
|
+
* @example
|
|
1701
|
+
* ```typescript
|
|
1702
|
+
* // Server side: single-shot actions
|
|
1703
|
+
* if (user.getButtonJustPressed("Jump")) {
|
|
1704
|
+
* player.jump(); // Fires once per press, not continuously
|
|
1705
|
+
* }
|
|
1706
|
+
*
|
|
1707
|
+
* if (user.getButtonJustPressed("ToggleInventory")) {
|
|
1708
|
+
* ui.toggleInventory(); // Won't toggle 5 times per click
|
|
1709
|
+
* }
|
|
1710
|
+
* ```
|
|
1711
|
+
*/
|
|
1712
|
+
getButtonJustPressed(buttonName: string): boolean;
|
|
1713
|
+
/**
|
|
1714
|
+
* Checks if a virtual button was just released this frame
|
|
1715
|
+
*
|
|
1716
|
+
* @param buttonName - Button name (e.g., "Fire", "ChargeShot")
|
|
1717
|
+
* @returns true if button just transitioned from true→false
|
|
1718
|
+
*
|
|
1719
|
+
* @example
|
|
1720
|
+
* ```typescript
|
|
1721
|
+
* // Server side: charge and release mechanics
|
|
1722
|
+
* if (user.getButton("ChargeShot")) {
|
|
1723
|
+
* weapon.charge(); // Accumulate power while held
|
|
1724
|
+
* }
|
|
1725
|
+
* if (user.getButtonJustReleased("ChargeShot")) {
|
|
1726
|
+
* weapon.fireChargedShot(); // Release when button released
|
|
1727
|
+
* }
|
|
1728
|
+
* ```
|
|
1729
|
+
*/
|
|
1730
|
+
getButtonJustReleased(buttonName: string): boolean;
|
|
1731
|
+
/**
|
|
1732
|
+
* Sets text input events for this frame
|
|
1733
|
+
* Called internally by input decoding system
|
|
1734
|
+
*
|
|
1735
|
+
* @param inputs - Array of key strings (e.g., ['a', 'Backspace', 'Enter'])
|
|
1736
|
+
* @internal
|
|
1737
|
+
*/
|
|
1738
|
+
setTextInputs(inputs: string[]): void;
|
|
1739
|
+
/**
|
|
1740
|
+
* Gets text input events for this frame
|
|
1741
|
+
* Use this in your update loop to handle input boxes, chat, etc.
|
|
1742
|
+
*
|
|
1743
|
+
* @returns Array of key strings typed this frame
|
|
1744
|
+
*
|
|
1745
|
+
* @example
|
|
1746
|
+
* ```typescript
|
|
1747
|
+
* // Server side: handle input box
|
|
1748
|
+
* const textInputs = user.getTextInputs();
|
|
1749
|
+
* for (const key of textInputs) {
|
|
1750
|
+
* if (key.length === 1) {
|
|
1751
|
+
* inputBox.addChar(key); // Regular character
|
|
1752
|
+
* } else if (key === 'Backspace') {
|
|
1753
|
+
* inputBox.deleteChar();
|
|
1754
|
+
* } else if (key === 'Enter') {
|
|
1755
|
+
* inputBox.submit();
|
|
1756
|
+
* }
|
|
1757
|
+
* }
|
|
1758
|
+
* ```
|
|
1759
|
+
*/
|
|
1760
|
+
getTextInputs(): string[];
|
|
1761
|
+
/**
|
|
1762
|
+
* Clears text input events (called after frame processing)
|
|
1763
|
+
* @internal
|
|
1764
|
+
*/
|
|
1765
|
+
clearTextInputs(): void;
|
|
1766
|
+
/**
|
|
1767
|
+
* Gets all defined axis names
|
|
1768
|
+
*
|
|
1769
|
+
* @returns Array of axis names
|
|
1770
|
+
*
|
|
1771
|
+
* @example
|
|
1772
|
+
* ```typescript
|
|
1773
|
+
* const axisNames = user.getAxisNames();
|
|
1774
|
+
* console.log(axisNames); // ["Horizontal", "Vertical", "CameraX", "CameraY"]
|
|
1775
|
+
* ```
|
|
1776
|
+
*/
|
|
1777
|
+
getAxisNames(): string[];
|
|
1778
|
+
/**
|
|
1779
|
+
* Gets all defined button names
|
|
1780
|
+
*
|
|
1781
|
+
* @returns Array of button names
|
|
1782
|
+
*
|
|
1783
|
+
* @example
|
|
1784
|
+
* ```typescript
|
|
1785
|
+
* const buttonNames = user.getButtonNames();
|
|
1786
|
+
* console.log(buttonNames); // ["Jump", "Fire", "Inventory", "Interact"]
|
|
1787
|
+
* ```
|
|
1788
|
+
*/
|
|
1789
|
+
getButtonNames(): string[];
|
|
1790
|
+
/**
|
|
1791
|
+
* Resets all axes to 0.0
|
|
1792
|
+
*
|
|
1793
|
+
* @example
|
|
1794
|
+
* ```typescript
|
|
1795
|
+
* user.clearAxes();
|
|
1796
|
+
* console.log(user.getAxis("Horizontal")); // 0.0
|
|
1797
|
+
* ```
|
|
1798
|
+
*/
|
|
1799
|
+
clearAxes(): void;
|
|
1800
|
+
/**
|
|
1801
|
+
* Resets all buttons to false
|
|
1802
|
+
*
|
|
1803
|
+
* @example
|
|
1804
|
+
* ```typescript
|
|
1805
|
+
* user.clearButtons();
|
|
1806
|
+
* console.log(user.getButton("Jump")); // false
|
|
1807
|
+
* ```
|
|
1808
|
+
*/
|
|
1809
|
+
clearButtons(): void;
|
|
1810
|
+
/**
|
|
1811
|
+
* Gets detailed information about mouse position
|
|
1812
|
+
*
|
|
1813
|
+
* Returns mouse position in multiple coordinate spaces:
|
|
1814
|
+
* - displayId: ID of the hovered display (or null if none)
|
|
1815
|
+
* - localX/localY: Position in the display (0 to sizeX/sizeY)
|
|
1816
|
+
* - worldX/worldY: Position in the virtual world (origin + local)
|
|
1817
|
+
*
|
|
1818
|
+
* Note: For now, we consider the mouse always hovers display 0
|
|
1819
|
+
* if mouseOver is true and at least one display exists.
|
|
1820
|
+
*
|
|
1821
|
+
* @returns Mouse position information, or null if no display
|
|
1822
|
+
*
|
|
1823
|
+
* @example
|
|
1824
|
+
* ```typescript
|
|
1825
|
+
* const mouseInfo = user.getMouseDisplayInfo();
|
|
1826
|
+
* if (mouseInfo) {
|
|
1827
|
+
* console.log(`Mouse over display ${mouseInfo.displayId}`);
|
|
1828
|
+
* console.log(`Local: ${mouseInfo.localX}, ${mouseInfo.localY}`);
|
|
1829
|
+
* console.log(`World: ${mouseInfo.worldX}, ${mouseInfo.worldY}`);
|
|
1830
|
+
* }
|
|
1831
|
+
* ```
|
|
1832
|
+
*/
|
|
1833
|
+
getMouseDisplayInfo(): {
|
|
1834
|
+
displayId: number | null;
|
|
1835
|
+
localX: number;
|
|
1836
|
+
localY: number;
|
|
1837
|
+
worldX: number;
|
|
1838
|
+
worldY: number;
|
|
1839
|
+
} | null;
|
|
1840
|
+
/**
|
|
1841
|
+
* Gets position information for a touch relative to the display
|
|
1842
|
+
*
|
|
1843
|
+
* @param touchId - Touch ID (0-9), default = 0 (first finger)
|
|
1844
|
+
* @returns Touch information (displayId, localX, localY, worldX, worldY) or null
|
|
1845
|
+
*
|
|
1846
|
+
* @example
|
|
1847
|
+
* ```typescript
|
|
1848
|
+
* const touchInfo = user.getTouchDisplayInfo(0);
|
|
1849
|
+
* if (touchInfo) {
|
|
1850
|
+
* console.log(`Touch 0 over display ${touchInfo.displayId}`);
|
|
1851
|
+
* console.log(`Local: ${touchInfo.localX}, ${touchInfo.localY}`);
|
|
1852
|
+
* console.log(`World: ${touchInfo.worldX}, ${touchInfo.worldY}`);
|
|
1853
|
+
* }
|
|
1854
|
+
* ```
|
|
1855
|
+
*/
|
|
1856
|
+
getTouchDisplayInfo(touchId?: number): {
|
|
1857
|
+
displayId: number | null;
|
|
1858
|
+
localX: number;
|
|
1859
|
+
localY: number;
|
|
1860
|
+
worldX: number;
|
|
1861
|
+
worldY: number;
|
|
1862
|
+
} | null;
|
|
1863
|
+
/**
|
|
1864
|
+
* Checks if the mouse is currently over a display
|
|
1865
|
+
*
|
|
1866
|
+
* @returns true if mouse is hovering a display, false otherwise
|
|
1867
|
+
*
|
|
1868
|
+
* @example
|
|
1869
|
+
* ```typescript
|
|
1870
|
+
* if (user.getIsMouseOnADisplay()) {
|
|
1871
|
+
* const info = user.getMouseDisplayInfo();
|
|
1872
|
+
* console.log(`Hovering display ${info.displayId}`);
|
|
1873
|
+
* }
|
|
1874
|
+
* ```
|
|
1875
|
+
*/
|
|
1876
|
+
getIsMouseOnADisplay(): boolean;
|
|
1877
|
+
/**
|
|
1878
|
+
* Gets the ID of the display currently hovered by the mouse
|
|
1879
|
+
*
|
|
1880
|
+
* @returns Display ID (0-255) or null if no display is hovered
|
|
1881
|
+
*
|
|
1882
|
+
* @example
|
|
1883
|
+
* ```typescript
|
|
1884
|
+
* const hoveredDisplayId = user.getMouseDisplayHover();
|
|
1885
|
+
* if (hoveredDisplayId !== null) {
|
|
1886
|
+
* console.log(`Hovering display ${hoveredDisplayId}`);
|
|
1887
|
+
* }
|
|
1888
|
+
* ```
|
|
1889
|
+
*/
|
|
1890
|
+
getMouseDisplayHover(): number | null;
|
|
1891
|
+
/**
|
|
1892
|
+
* Finds a layer by its ID
|
|
1893
|
+
*
|
|
1894
|
+
* @param id - ID of the layer to find
|
|
1895
|
+
* @returns Found layer or null
|
|
1896
|
+
* @internal - Used for UpdatePacket reconstruction
|
|
1897
|
+
*/
|
|
1898
|
+
private findLayerById;
|
|
1899
|
+
/**
|
|
1900
|
+
* Applies an UpdatePacket to this user (CLIENT-SIDE RECONSTRUCTION)
|
|
1901
|
+
*
|
|
1902
|
+
* This method reconstructs the user state from an UpdatePacket
|
|
1903
|
+
* received from the server. It updates displays (viewports) and layers
|
|
1904
|
+
* incrementally according to updateFlags.
|
|
1905
|
+
*
|
|
1906
|
+
* IMPORTANT: This method must be called in CLIENT mode only.
|
|
1907
|
+
* The server generates packets, the client applies them.
|
|
1908
|
+
*
|
|
1909
|
+
* @param packet - Decoded UpdatePacket received from server
|
|
1910
|
+
*
|
|
1911
|
+
* @example
|
|
1912
|
+
* ```typescript
|
|
1913
|
+
* // Client side (ClientRuntime)
|
|
1914
|
+
* const decoder = new UpdatePacketDecoder();
|
|
1915
|
+
* const packet = decoder.decode(receivedBuffer);
|
|
1916
|
+
* user.applyUpdate(packet);
|
|
1917
|
+
* ```
|
|
1918
|
+
*/
|
|
1919
|
+
applyUpdate(packet: UpdatePacket): void;
|
|
1920
|
+
/**
|
|
1921
|
+
* Updates displays from an UpdatePacket
|
|
1922
|
+
*
|
|
1923
|
+
* Adjusts the number of displays and updates their origins/sizes.
|
|
1924
|
+
*
|
|
1925
|
+
* @private
|
|
1926
|
+
* @param networkDisplays - Displays from packet
|
|
1927
|
+
*/
|
|
1928
|
+
private updateDisplaysFromPacket;
|
|
1929
|
+
/**
|
|
1930
|
+
* Updates layers from an UpdatePacket (INCREMENTAL LOGIC)
|
|
1931
|
+
*
|
|
1932
|
+
* This method reconstructs layers according to updateFlags:
|
|
1933
|
+
* - 0x01: Update origin
|
|
1934
|
+
* - 0x02: Update z-order
|
|
1935
|
+
* - 0x04: Update orders (replace or add according to SET/ADD flag)
|
|
1936
|
+
*
|
|
1937
|
+
* If a layer doesn't exist yet, it is created automatically.
|
|
1938
|
+
*
|
|
1939
|
+
* IMPORTANT: In client mode, orders are automatically rasterized
|
|
1940
|
+
* when calling setOrders() / addOrders().
|
|
1941
|
+
*
|
|
1942
|
+
* @private
|
|
1943
|
+
* @param networkLayers - Layers from packet with their updateFlags
|
|
1944
|
+
*/
|
|
1945
|
+
private updateLayersFromPacket;
|
|
1946
|
+
/**
|
|
1947
|
+
* Defines an axis binding
|
|
1948
|
+
*
|
|
1949
|
+
* Associates a bindingId (0-255) with an axis name and its physical sources.
|
|
1950
|
+
* The client will receive this mapping via a JSON LoadPacket.
|
|
1951
|
+
*
|
|
1952
|
+
* Sources are summed on the server side after receiving raw values.
|
|
1953
|
+
*
|
|
1954
|
+
* @param bindingId - Unique axis ID (0-255)
|
|
1955
|
+
* @param name - Axis name (e.g., "MoveHorizontal", "CameraX")
|
|
1956
|
+
* @param sources - Physical sources (keyboard, gamepad, mouse, gyro, touch)
|
|
1957
|
+
* @param min - Minimum value (default: -1.0)
|
|
1958
|
+
* @param max - Maximum value (default: +1.0)
|
|
1959
|
+
* @param defaultValue - Default value (default: 0.0)
|
|
1960
|
+
*
|
|
1961
|
+
* @example
|
|
1962
|
+
* ```typescript
|
|
1963
|
+
* import { InputDeviceType, KeyboardInput, GamepadInput } from '@utsp/types';
|
|
1964
|
+
*
|
|
1965
|
+
* user.defineAxisBinding(0, "MoveHorizontal", [
|
|
1966
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, negativeKey: KeyboardInput.ArrowLeft, positiveKey: KeyboardInput.ArrowRight },
|
|
1967
|
+
* { sourceId: 1, type: InputDeviceType.Gamepad, gamepadIndex: 0, axis: GamepadInput.LeftStickX }
|
|
1968
|
+
* ], -1.0, 1.0, 0.0);
|
|
1969
|
+
* ```
|
|
1970
|
+
*/
|
|
1971
|
+
defineAxisBinding(bindingId: number, name: string, sources?: AxisSource[], min?: number, max?: number, defaultValue?: number): void;
|
|
1972
|
+
/**
|
|
1973
|
+
* Defines a button binding
|
|
1974
|
+
*
|
|
1975
|
+
* Associates a bindingId (0-255) with a button name and its physical sources.
|
|
1976
|
+
* Sources use OR logic (at least one pressed source = button pressed).
|
|
1977
|
+
*
|
|
1978
|
+
* @param bindingId - Unique button ID (0-255)
|
|
1979
|
+
* @param name - Button name (e.g., "Jump", "Attack")
|
|
1980
|
+
* @param sources - Physical sources (keyboard, gamepad, mouse, touch)
|
|
1981
|
+
* @param defaultValue - Default value (default: false)
|
|
1982
|
+
*
|
|
1983
|
+
* @example
|
|
1984
|
+
* ```typescript
|
|
1985
|
+
* import { InputDeviceType, KeyboardInput, GamepadInput } from '@utsp/types';
|
|
1986
|
+
*
|
|
1987
|
+
* user.defineButtonBinding(0, "Jump", [
|
|
1988
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, key: KeyboardInput.Space },
|
|
1989
|
+
* { sourceId: 1, type: InputDeviceType.Gamepad, gamepadIndex: 0, button: GamepadInput.A }
|
|
1990
|
+
* ], false);
|
|
1991
|
+
* ```
|
|
1992
|
+
*/
|
|
1993
|
+
defineButtonBinding(bindingId: number, name: string, sources?: ButtonSource[], defaultValue?: boolean): void;
|
|
1994
|
+
/**
|
|
1995
|
+
* Defines multiple axis bindings at once
|
|
1996
|
+
*
|
|
1997
|
+
* @param axes - Array of axis definitions
|
|
1998
|
+
*
|
|
1999
|
+
* @example
|
|
2000
|
+
* ```typescript
|
|
2001
|
+
* import { InputDeviceType, KeyboardInput } from '@utsp/types';
|
|
2002
|
+
*
|
|
2003
|
+
* user.defineAxisBindings([
|
|
2004
|
+
* {
|
|
2005
|
+
* bindingId: 0,
|
|
2006
|
+
* name: "MoveHorizontal",
|
|
2007
|
+
* sources: [
|
|
2008
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, negativeKey: KeyboardInput.ArrowLeft, positiveKey: KeyboardInput.ArrowRight }
|
|
2009
|
+
* ]
|
|
2010
|
+
* },
|
|
2011
|
+
* { bindingId: 1, name: "MoveVertical", sources: [] },
|
|
2012
|
+
* ]);
|
|
2013
|
+
* ```
|
|
2014
|
+
*/
|
|
2015
|
+
defineAxisBindings(axes: Array<{
|
|
2016
|
+
bindingId: number;
|
|
2017
|
+
name: string;
|
|
2018
|
+
sources?: AxisSource[];
|
|
2019
|
+
min?: number;
|
|
2020
|
+
max?: number;
|
|
2021
|
+
defaultValue?: number;
|
|
2022
|
+
}>): void;
|
|
2023
|
+
/**
|
|
2024
|
+
* Defines multiple button bindings at once
|
|
2025
|
+
*
|
|
2026
|
+
* @param buttons - Array of button definitions
|
|
2027
|
+
*
|
|
2028
|
+
* @example
|
|
2029
|
+
* ```typescript
|
|
2030
|
+
* import { InputDeviceType, KeyboardInput } from '@utsp/types';
|
|
2031
|
+
*
|
|
2032
|
+
* user.defineButtonBindings([
|
|
2033
|
+
* {
|
|
2034
|
+
* bindingId: 0,
|
|
2035
|
+
* name: "Jump",
|
|
2036
|
+
* sources: [
|
|
2037
|
+
* { sourceId: 0, type: InputDeviceType.Keyboard, key: KeyboardInput.Space }
|
|
2038
|
+
* ]
|
|
2039
|
+
* },
|
|
2040
|
+
* { bindingId: 1, name: "Attack", sources: [] },
|
|
2041
|
+
* ]);
|
|
2042
|
+
* ```
|
|
2043
|
+
*/
|
|
2044
|
+
defineButtonBindings(buttons: Array<{
|
|
2045
|
+
bindingId: number;
|
|
2046
|
+
name: string;
|
|
2047
|
+
sources?: ButtonSource[];
|
|
2048
|
+
defaultValue?: boolean;
|
|
2049
|
+
}>): void;
|
|
2050
|
+
/**
|
|
2051
|
+
* Generates the JSON LoadPacket containing input bindings
|
|
2052
|
+
*
|
|
2053
|
+
* This packet must be sent to the client via the Load channel to indicate
|
|
2054
|
+
* which axes and buttons it should capture and send back.
|
|
2055
|
+
*
|
|
2056
|
+
* Format: JSON string (not binary for now as it's sent rarely)
|
|
2057
|
+
*
|
|
2058
|
+
* @returns JSON LoadPacket as string
|
|
2059
|
+
*
|
|
2060
|
+
* @example
|
|
2061
|
+
* ```typescript
|
|
2062
|
+
* // Server: Define bindings
|
|
2063
|
+
* user.defineAxisBinding(0, "MoveHorizontal");
|
|
2064
|
+
* user.defineAxisBinding(1, "MoveVertical");
|
|
2065
|
+
* user.defineButtonBinding(0, "Jump");
|
|
2066
|
+
*
|
|
2067
|
+
* // Generate and send to client
|
|
2068
|
+
* const packet = user.getInputBindingsLoadPacket();
|
|
2069
|
+
* websocket.send(packet);
|
|
2070
|
+
* ```
|
|
2071
|
+
*/
|
|
2072
|
+
getInputBindingsLoadPacket(): string;
|
|
2073
|
+
/**
|
|
2074
|
+
* Applies Input Bindings received from server (CLIENT-SIDE)
|
|
2075
|
+
*
|
|
2076
|
+
* This method parses the bindings JSON and configures them in the registry.
|
|
2077
|
+
* The client can then capture inputs and send them compressed.
|
|
2078
|
+
*
|
|
2079
|
+
* @param json - JSON string of bindings from getInputBindingsLoadPacket()
|
|
2080
|
+
*
|
|
2081
|
+
* @example
|
|
2082
|
+
* ```typescript
|
|
2083
|
+
* // Client side
|
|
2084
|
+
* websocket.on('input-bindings', (json: string) => {
|
|
2085
|
+
* user.applyInputBindingsLoadPacket(json);
|
|
2086
|
+
* console.log('Input bindings configured');
|
|
2087
|
+
* });
|
|
2088
|
+
* ```
|
|
2089
|
+
*/
|
|
2090
|
+
applyInputBindingsLoadPacket(json: string): void;
|
|
2091
|
+
/**
|
|
2092
|
+
* Gets this user's InputBindingRegistry
|
|
2093
|
+
*
|
|
2094
|
+
* @returns InputBindingRegistry instance
|
|
2095
|
+
*
|
|
2096
|
+
* @example
|
|
2097
|
+
* ```typescript
|
|
2098
|
+
* const registry = user.getInputBindingRegistry();
|
|
2099
|
+
* console.log(registry.toString());
|
|
2100
|
+
* console.log(`Axes: ${registry.getAxisCount()}`);
|
|
2101
|
+
* console.log(`Buttons: ${registry.getButtonCount()}`);
|
|
2102
|
+
* ```
|
|
2103
|
+
*/
|
|
2104
|
+
getInputBindingRegistry(): InputBindingRegistry;
|
|
2105
|
+
/**
|
|
2106
|
+
* Gets the UserStats object to access this user's statistics
|
|
2107
|
+
*
|
|
2108
|
+
* @returns The user's UserStats instance
|
|
2109
|
+
*
|
|
2110
|
+
* @example
|
|
2111
|
+
* ```typescript
|
|
2112
|
+
* // Enable stats
|
|
2113
|
+
* user.getStats().setEnabled(true);
|
|
2114
|
+
*
|
|
2115
|
+
* // After a tick...
|
|
2116
|
+
* const stats = user.getStats();
|
|
2117
|
+
* console.log(`User ${stats.userName}:`);
|
|
2118
|
+
* console.log(` Displays: ${stats.displayCount}`);
|
|
2119
|
+
* console.log(` Layers: ${stats.visibleLayers}/${stats.totalLayers}`);
|
|
2120
|
+
* console.log(` Orders: ${stats.totalOrders}`);
|
|
2121
|
+
* console.log(` Packet size: ${stats.totalPacketSize} bytes`);
|
|
2122
|
+
* ```
|
|
2123
|
+
*/
|
|
2124
|
+
getStats(): UserStats;
|
|
2125
|
+
/**
|
|
2126
|
+
* Gets the bindingId of an axis from its name
|
|
2127
|
+
*
|
|
2128
|
+
* @param name - Axis name
|
|
2129
|
+
* @returns bindingId or null if not found
|
|
2130
|
+
*/
|
|
2131
|
+
getAxisBindingId(name: string): number | null;
|
|
2132
|
+
/**
|
|
2133
|
+
* Gets the bindingId of a button from its name
|
|
2134
|
+
*
|
|
2135
|
+
* @param name - Button name
|
|
2136
|
+
* @returns bindingId or null if not found
|
|
2137
|
+
*/
|
|
2138
|
+
getButtonBindingId(name: string): number | null;
|
|
2139
|
+
/**
|
|
2140
|
+
* Decodes and applies a compressed input buffer received from client (format v3)
|
|
2141
|
+
*
|
|
2142
|
+
* This method:
|
|
2143
|
+
* 1. Decodes the binary buffer (v3 MINIMAL format - without counts)
|
|
2144
|
+
* 2. Stores values in axes/buttons Maps
|
|
2145
|
+
* 3. Updates mouse position + displayId
|
|
2146
|
+
*
|
|
2147
|
+
* Format v3: Buffer does NOT contain axes/buttons counts.
|
|
2148
|
+
* Server uses its internal registry to know the expected structure.
|
|
2149
|
+
*
|
|
2150
|
+
* IMPORTANT: Client and server must have the SAME bindings defined!
|
|
2151
|
+
*
|
|
2152
|
+
* @param buffer - Encoded buffer received from client via WebSocket
|
|
2153
|
+
*
|
|
2154
|
+
* @example
|
|
2155
|
+
* ```typescript
|
|
2156
|
+
* // Server receives buffer from client
|
|
2157
|
+
* websocket.on('message', (data) => {
|
|
2158
|
+
* const buffer = new Uint8Array(data);
|
|
2159
|
+
* user.decodeAndApplyCompressedInput(buffer);
|
|
2160
|
+
*
|
|
2161
|
+
* // Values are now available
|
|
2162
|
+
* const move = user.getAxis("MoveHorizontal");
|
|
2163
|
+
* if (user.getButton("Jump")) { ... }
|
|
2164
|
+
* });
|
|
2165
|
+
* ```
|
|
2166
|
+
*/
|
|
2167
|
+
decodeAndApplyCompressedInput(buffer: Uint8Array): void;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* UTSP engine performance statistics
|
|
2172
|
+
* Collects metrics per tick for analysis and optimization
|
|
2173
|
+
*/
|
|
2174
|
+
interface TickStats {
|
|
2175
|
+
tick: number;
|
|
2176
|
+
timestamp: number;
|
|
2177
|
+
totalOrders: number;
|
|
2178
|
+
ordersByLayer: Map<number, number>;
|
|
2179
|
+
ordersByType: Map<number, number>;
|
|
2180
|
+
totalLayers: number;
|
|
2181
|
+
visibleLayers: number;
|
|
2182
|
+
layersPerDisplay: Map<number, number>;
|
|
2183
|
+
updatePacketSize: number;
|
|
2184
|
+
displayHeaderSize: number;
|
|
2185
|
+
layerHeaderSize: number;
|
|
2186
|
+
orderDataSize: number;
|
|
2187
|
+
compressionRatio: number;
|
|
2188
|
+
totalCells: number;
|
|
2189
|
+
nonEmptyCells: number;
|
|
2190
|
+
cellsWithBackground: number;
|
|
2191
|
+
rasterizationTimeMs: number;
|
|
2192
|
+
encodingTimeMs: number;
|
|
2193
|
+
}
|
|
2194
|
+
declare class CoreStats {
|
|
2195
|
+
private enabled;
|
|
2196
|
+
private currentStats;
|
|
2197
|
+
/**
|
|
2198
|
+
* Enables or disables statistics collection
|
|
2199
|
+
*/
|
|
2200
|
+
setEnabled(enabled: boolean): void;
|
|
2201
|
+
isEnabled(): boolean;
|
|
2202
|
+
/** Current tick number (0 if no stats) */
|
|
2203
|
+
get tick(): number;
|
|
2204
|
+
/** Current tick timestamp */
|
|
2205
|
+
get timestamp(): number;
|
|
2206
|
+
/** Total orders processed this tick */
|
|
2207
|
+
get totalOrders(): number;
|
|
2208
|
+
/** Orders per layer ID */
|
|
2209
|
+
get ordersByLayer(): Map<number, number>;
|
|
2210
|
+
/** Orders per type (0x01, 0x02, etc.) */
|
|
2211
|
+
get ordersByType(): Map<number, number>;
|
|
2212
|
+
/** Nombre total de layers */
|
|
2213
|
+
get totalLayers(): number;
|
|
2214
|
+
/** Layers visibles (qui intersectent un display) */
|
|
2215
|
+
get visibleLayers(): number;
|
|
2216
|
+
/** Layers visibles par display ID */
|
|
2217
|
+
get layersPerDisplay(): Map<number, number>;
|
|
2218
|
+
/** Total encoded UpdatePacket size (bytes) */
|
|
2219
|
+
get updatePacketSize(): number;
|
|
2220
|
+
/** Display header size (bytes) */
|
|
2221
|
+
get displayHeaderSize(): number;
|
|
2222
|
+
/** Layer header size (bytes) */
|
|
2223
|
+
get layerHeaderSize(): number;
|
|
2224
|
+
/** Order data size (bytes) */
|
|
2225
|
+
get orderDataSize(): number;
|
|
2226
|
+
/** Estimated gzip compression ratio (0.25 = 75% compression) */
|
|
2227
|
+
get compressionRatio(): number;
|
|
2228
|
+
/** Estimated size after gzip compression (bytes) */
|
|
2229
|
+
get compressedPacketSize(): number;
|
|
2230
|
+
/** Total number of rendered cells */
|
|
2231
|
+
get totalCells(): number;
|
|
2232
|
+
/** Non-empty cells (char !== ' ') */
|
|
2233
|
+
get nonEmptyCells(): number;
|
|
2234
|
+
/** Cells with colored background */
|
|
2235
|
+
get cellsWithBackground(): number;
|
|
2236
|
+
/** Rasterization time (ms) */
|
|
2237
|
+
get rasterizationTimeMs(): number;
|
|
2238
|
+
/** Encoding time (ms) */
|
|
2239
|
+
get encodingTimeMs(): number;
|
|
2240
|
+
/** Static/dynamic split information for the last processed user */
|
|
2241
|
+
get packetSplit(): {
|
|
2242
|
+
userId: string;
|
|
2243
|
+
displayCount: number;
|
|
2244
|
+
staticLayerCount: number;
|
|
2245
|
+
dynamicLayerCount: number;
|
|
2246
|
+
} | undefined;
|
|
2247
|
+
/** Details of all layers processed this tick */
|
|
2248
|
+
get layerDetails(): Array<{
|
|
2249
|
+
layerId: number;
|
|
2250
|
+
isStatic: boolean;
|
|
2251
|
+
orderCount: number;
|
|
2252
|
+
updateFlags: number;
|
|
2253
|
+
}> | undefined;
|
|
2254
|
+
/**
|
|
2255
|
+
* Starts collecting statistics for a new tick
|
|
2256
|
+
*/
|
|
2257
|
+
startTick(tickNumber: number): void;
|
|
2258
|
+
/**
|
|
2259
|
+
* Records orders for a layer
|
|
2260
|
+
*/
|
|
2261
|
+
recordLayerOrders(layerId: number, orders: any[]): void;
|
|
2262
|
+
/**
|
|
2263
|
+
* Records the number of layers
|
|
2264
|
+
*/
|
|
2265
|
+
recordLayers(total: number, visible: number): void;
|
|
2266
|
+
/**
|
|
2267
|
+
* Records visible layers per display
|
|
2268
|
+
*/
|
|
2269
|
+
recordDisplayLayers(displayId: number, layerCount: number): void;
|
|
2270
|
+
/**
|
|
2271
|
+
* Records the encoded UpdatePacket size
|
|
2272
|
+
*/
|
|
2273
|
+
recordUpdatePacketSize(totalBytes: number, displayHeaderBytes: number, layerHeaderBytes: number, orderDataBytes: number): void;
|
|
2274
|
+
/**
|
|
2275
|
+
* Records static/dynamic split information
|
|
2276
|
+
*/
|
|
2277
|
+
recordPacketSplit(userId: string, displayCount: number, staticLayerCount: number, dynamicLayerCount: number): void;
|
|
2278
|
+
/**
|
|
2279
|
+
* Records individual layer information
|
|
2280
|
+
*/
|
|
2281
|
+
recordLayerInfo(layerId: number, isStatic: boolean, orderCount: number, updateFlags: number): void;
|
|
2282
|
+
/**
|
|
2283
|
+
* Records rendered cell statistics
|
|
2284
|
+
*/
|
|
2285
|
+
recordRenderStats(totalCells: number, nonEmptyCells: number, cellsWithBg: number): void;
|
|
2286
|
+
/**
|
|
2287
|
+
* Records rasterization time
|
|
2288
|
+
*/
|
|
2289
|
+
recordRasterizationTime(timeMs: number): void;
|
|
2290
|
+
/**
|
|
2291
|
+
* Records encoding time
|
|
2292
|
+
*/
|
|
2293
|
+
recordEncodingTime(timeMs: number): void;
|
|
2294
|
+
/**
|
|
2295
|
+
* Finalizes stats for the current tick
|
|
2296
|
+
* Stats remain available until the next startTick()
|
|
2297
|
+
*/
|
|
2298
|
+
endTick(): void;
|
|
2299
|
+
/**
|
|
2300
|
+
* Resets statistics
|
|
2301
|
+
*/
|
|
2302
|
+
reset(): void;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
/**
|
|
2306
|
+
* WebFontRegistry - Registry for CSS-based fonts
|
|
2307
|
+
*/
|
|
2308
|
+
|
|
2309
|
+
/**
|
|
2310
|
+
* Registry for managing WebFont instances
|
|
2311
|
+
* Each font is identified by a unique fontId (0-255)
|
|
2312
|
+
*/
|
|
2313
|
+
declare class WebFontRegistry {
|
|
2314
|
+
private fonts;
|
|
2315
|
+
/**
|
|
2316
|
+
* Load a new WebFont into the registry
|
|
2317
|
+
* @param fontId Unique font identifier (0-255)
|
|
2318
|
+
* @param config WebFont configuration
|
|
2319
|
+
* @throws Error if font ID already exists
|
|
2320
|
+
*/
|
|
2321
|
+
loadFont(fontId: number, config: WebFontConfig): void;
|
|
2322
|
+
/**
|
|
2323
|
+
* Get a WebFont by ID
|
|
2324
|
+
* @param fontId Font identifier
|
|
2325
|
+
* @returns WebFont instance or undefined if not found
|
|
2326
|
+
*/
|
|
2327
|
+
getFont(fontId: number): WebFont | undefined;
|
|
2328
|
+
/**
|
|
2329
|
+
* Check if a font exists in the registry
|
|
2330
|
+
* @param fontId Font identifier
|
|
2331
|
+
* @returns true if font exists, false otherwise
|
|
2332
|
+
*/
|
|
2333
|
+
hasFont(fontId: number): boolean;
|
|
2334
|
+
/**
|
|
2335
|
+
* Remove a WebFont from the registry
|
|
2336
|
+
* @param fontId Font identifier
|
|
2337
|
+
* @returns true if font was removed, false if not found
|
|
2338
|
+
*/
|
|
2339
|
+
unloadFont(fontId: number): boolean;
|
|
2340
|
+
/**
|
|
2341
|
+
* Remove all fonts from the registry
|
|
2342
|
+
*/
|
|
2343
|
+
clearFonts(): void;
|
|
2344
|
+
/**
|
|
2345
|
+
* Get all font IDs in the registry
|
|
2346
|
+
* @returns Array of font IDs, sorted in ascending order
|
|
2347
|
+
*/
|
|
2348
|
+
getFontIds(): number[];
|
|
2349
|
+
/**
|
|
2350
|
+
* Get all WebFont instances in the registry
|
|
2351
|
+
* @returns Array of WebFont instances, sorted by font ID
|
|
2352
|
+
*/
|
|
2353
|
+
getAllFonts(): WebFont[];
|
|
2354
|
+
/**
|
|
2355
|
+
* Get the number of fonts in the registry
|
|
2356
|
+
* @returns Number of fonts
|
|
2357
|
+
*/
|
|
2358
|
+
getFontCount(): number;
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
/**
|
|
2362
|
+
* BitmapFontRegistry - Registry for pixel-based bitmap fonts
|
|
2363
|
+
*/
|
|
2364
|
+
|
|
2365
|
+
/**
|
|
2366
|
+
* Registry for managing BitmapFont instances
|
|
2367
|
+
* Each font is identified by a unique fontId (0-255)
|
|
2368
|
+
* BitmapFonts correspond to LoadType 0x04 (Charset) in UTSP protocol
|
|
2369
|
+
*/
|
|
2370
|
+
declare class BitmapFontRegistry {
|
|
2371
|
+
private fonts;
|
|
2372
|
+
/**
|
|
2373
|
+
* Load a new BitmapFont into the registry
|
|
2374
|
+
* @param fontId Unique font identifier (0-255)
|
|
2375
|
+
* @param config BitmapFont configuration
|
|
2376
|
+
* @throws Error if font ID already exists
|
|
2377
|
+
*/
|
|
2378
|
+
loadFont(fontId: number, config: BitmapFontConfig): void;
|
|
2379
|
+
/**
|
|
2380
|
+
* Get a BitmapFont by ID
|
|
2381
|
+
* @param fontId Font identifier
|
|
2382
|
+
* @returns BitmapFont instance or undefined if not found
|
|
2383
|
+
*/
|
|
2384
|
+
getFont(fontId: number): BitmapFont | undefined;
|
|
2385
|
+
/**
|
|
2386
|
+
* Check if a font exists in the registry
|
|
2387
|
+
* @param fontId Font identifier
|
|
2388
|
+
* @returns true if font exists, false otherwise
|
|
2389
|
+
*/
|
|
2390
|
+
hasFont(fontId: number): boolean;
|
|
2391
|
+
/**
|
|
2392
|
+
* Remove a BitmapFont from the registry
|
|
2393
|
+
* @param fontId Font identifier
|
|
2394
|
+
* @returns true if font was removed, false if not found
|
|
2395
|
+
*/
|
|
2396
|
+
unloadFont(fontId: number): boolean;
|
|
2397
|
+
/**
|
|
2398
|
+
* Remove all fonts from the registry
|
|
2399
|
+
*/
|
|
2400
|
+
clearFonts(): void;
|
|
2401
|
+
/**
|
|
2402
|
+
* Get all font IDs in the registry
|
|
2403
|
+
* @returns Array of font IDs, sorted in ascending order
|
|
2404
|
+
*/
|
|
2405
|
+
getFontIds(): number[];
|
|
2406
|
+
/**
|
|
2407
|
+
* Get all BitmapFont instances in the registry
|
|
2408
|
+
* @returns Array of BitmapFont instances, sorted by font ID
|
|
2409
|
+
*/
|
|
2410
|
+
getAllFonts(): BitmapFont[];
|
|
2411
|
+
/**
|
|
2412
|
+
* Get the number of fonts in the registry
|
|
2413
|
+
* @returns Number of fonts
|
|
2414
|
+
*/
|
|
2415
|
+
getFontCount(): number;
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
/**
|
|
2419
|
+
* Engine execution context type
|
|
2420
|
+
*/
|
|
2421
|
+
type CoreMode = 'server' | 'client' | 'standalone';
|
|
2422
|
+
/**
|
|
2423
|
+
* UTSP engine configuration options
|
|
2424
|
+
*/
|
|
2425
|
+
interface CoreOptions {
|
|
2426
|
+
/**
|
|
2427
|
+
* Execution mode: "server", "client" or "standalone"
|
|
2428
|
+
*
|
|
2429
|
+
* - "server": Server-side engine
|
|
2430
|
+
* → Marks layers as dirty (change tracking)
|
|
2431
|
+
* → Does NOT rasterize (CPU savings, client-side rasterization)
|
|
2432
|
+
* → Manages multiple users (limited by maxUsers)
|
|
2433
|
+
*
|
|
2434
|
+
* - "client": Client-side engine
|
|
2435
|
+
* → Does NOT mark as dirty (no tracking needed)
|
|
2436
|
+
* → Rasterizes immediately (local rendering for display)
|
|
2437
|
+
* → Manages ONE local user only (fixed limit)
|
|
2438
|
+
*
|
|
2439
|
+
* - "standalone": Standalone engine (preview, tests, debug)
|
|
2440
|
+
* → Marks as dirty AND rasterizes
|
|
2441
|
+
* → Manages multiple users
|
|
2442
|
+
* → Useful for getRenderState(), tests, simulations
|
|
2443
|
+
*
|
|
2444
|
+
* @default "server"
|
|
2445
|
+
*/
|
|
2446
|
+
mode?: CoreMode;
|
|
2447
|
+
/**
|
|
2448
|
+
* Maximum number of users allowed (server mode only)
|
|
2449
|
+
*
|
|
2450
|
+
* In client mode, this option is ignored (fixed limit of 1 user)
|
|
2451
|
+
*
|
|
2452
|
+
* @default 64
|
|
2453
|
+
*/
|
|
2454
|
+
maxUsers?: number;
|
|
2455
|
+
/**
|
|
2456
|
+
* Enable strict validations (useful in development)
|
|
2457
|
+
*
|
|
2458
|
+
* @default false
|
|
2459
|
+
*/
|
|
2460
|
+
strictMode?: boolean;
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Core - UTSP data management engine
|
|
2464
|
+
*
|
|
2465
|
+
* Passive API: no loop, no network, no callbacks.
|
|
2466
|
+
* Parent package (utsp-server, utsp-client) controls execution flow.
|
|
2467
|
+
*
|
|
2468
|
+
* Responsibilities:
|
|
2469
|
+
* - Store and manage users
|
|
2470
|
+
* - Provide data manipulation methods
|
|
2471
|
+
* - Pure and predictable API
|
|
2472
|
+
*
|
|
2473
|
+
* What the core does NOT do:
|
|
2474
|
+
* - No tick loop (server/client manages it)
|
|
2475
|
+
* - No network (server/client manages it)
|
|
2476
|
+
* - No callbacks/events (core is a passive slave)
|
|
2477
|
+
*/
|
|
2478
|
+
declare class Core {
|
|
2479
|
+
private users;
|
|
2480
|
+
private readonly mode;
|
|
2481
|
+
private readonly maxUsers;
|
|
2482
|
+
private readonly strictMode;
|
|
2483
|
+
private currentTick;
|
|
2484
|
+
private encoder;
|
|
2485
|
+
private displayRasterizer;
|
|
2486
|
+
private colorPalette;
|
|
2487
|
+
private static readonly ANSI_VGA_COLORS;
|
|
2488
|
+
private stats;
|
|
2489
|
+
private spriteRegistry;
|
|
2490
|
+
private webFontRegistry;
|
|
2491
|
+
private bitmapFontRegistry;
|
|
2492
|
+
private activeWebFontId;
|
|
2493
|
+
private _renderCallCount;
|
|
2494
|
+
private onPaletteChangedCallback?;
|
|
2495
|
+
private onBitmapFontChangedCallback?;
|
|
2496
|
+
/**
|
|
2497
|
+
* Creates a new UTSP engine instance
|
|
2498
|
+
*
|
|
2499
|
+
* @param options - Configuration options
|
|
2500
|
+
*
|
|
2501
|
+
* @example
|
|
2502
|
+
* ```typescript
|
|
2503
|
+
* // Server with 100 max users
|
|
2504
|
+
* const engine = new Core({
|
|
2505
|
+
* mode: "server",
|
|
2506
|
+
* maxUsers: 100
|
|
2507
|
+
* });
|
|
2508
|
+
*
|
|
2509
|
+
* // Simple client
|
|
2510
|
+
* const engine = new Core({
|
|
2511
|
+
* mode: "client"
|
|
2512
|
+
* });
|
|
2513
|
+
*
|
|
2514
|
+
* // Default mode (server)
|
|
2515
|
+
* const engine = new Core();
|
|
2516
|
+
* ```
|
|
2517
|
+
*/
|
|
2518
|
+
constructor(options?: CoreOptions);
|
|
2519
|
+
/**
|
|
2520
|
+
* Initialize default color palette (15 reserved UI colors + free colors)
|
|
2521
|
+
* @private
|
|
2522
|
+
*/
|
|
2523
|
+
private initializeDefaultPalette;
|
|
2524
|
+
/**
|
|
2525
|
+
* Returns current execution mode
|
|
2526
|
+
*
|
|
2527
|
+
* @returns "server", "client" or "standalone"
|
|
2528
|
+
*/
|
|
2529
|
+
getMode(): CoreMode;
|
|
2530
|
+
/**
|
|
2531
|
+
* Returns maximum allowed users
|
|
2532
|
+
*
|
|
2533
|
+
* @returns Max number of users
|
|
2534
|
+
*/
|
|
2535
|
+
getMaxUsers(): number;
|
|
2536
|
+
/**
|
|
2537
|
+
* Indicates if strict mode is enabled
|
|
2538
|
+
*
|
|
2539
|
+
* @returns true if strict mode is enabled
|
|
2540
|
+
*/
|
|
2541
|
+
isStrictMode(): boolean;
|
|
2542
|
+
/**
|
|
2543
|
+
* Checks if core is in server mode
|
|
2544
|
+
*
|
|
2545
|
+
* @returns true if server mode
|
|
2546
|
+
*/
|
|
2547
|
+
isServer(): boolean;
|
|
2548
|
+
/**
|
|
2549
|
+
* Checks if core is in client mode
|
|
2550
|
+
*
|
|
2551
|
+
* @returns true if client mode
|
|
2552
|
+
*/
|
|
2553
|
+
isClient(): boolean;
|
|
2554
|
+
/**
|
|
2555
|
+
* Checks if core is in standalone mode
|
|
2556
|
+
*
|
|
2557
|
+
* @returns true if standalone mode
|
|
2558
|
+
*/
|
|
2559
|
+
isStandalone(): boolean;
|
|
2560
|
+
/**
|
|
2561
|
+
* Creates a new user in the engine
|
|
2562
|
+
*
|
|
2563
|
+
* @param id - Unique user ID (string)
|
|
2564
|
+
* @param name - User name
|
|
2565
|
+
* @returns Created user
|
|
2566
|
+
* @throws Error if ID already exists
|
|
2567
|
+
*
|
|
2568
|
+
* @example
|
|
2569
|
+
* ```typescript
|
|
2570
|
+
* const engine = new Core();
|
|
2571
|
+
* const user = engine.createUser("user1", "Alice");
|
|
2572
|
+
* ```
|
|
2573
|
+
*/
|
|
2574
|
+
createUser(id: string, name: string): User;
|
|
2575
|
+
/**
|
|
2576
|
+
* Gets a user by ID
|
|
2577
|
+
*
|
|
2578
|
+
* @param id - User ID (string)
|
|
2579
|
+
* @returns The user or null if not found
|
|
2580
|
+
*
|
|
2581
|
+
* @example
|
|
2582
|
+
* ```typescript
|
|
2583
|
+
* const user = engine.getUser("user1");
|
|
2584
|
+
* if (user) {
|
|
2585
|
+
* console.log(user.name);
|
|
2586
|
+
* }
|
|
2587
|
+
* ```
|
|
2588
|
+
*/
|
|
2589
|
+
getUser(id: string): User | null;
|
|
2590
|
+
/**
|
|
2591
|
+
* Gets all users from the engine
|
|
2592
|
+
*
|
|
2593
|
+
* @returns Array of all users
|
|
2594
|
+
*
|
|
2595
|
+
* @example
|
|
2596
|
+
* ```typescript
|
|
2597
|
+
* for (const user of engine.getUsers()) {
|
|
2598
|
+
* console.log(`User ${user.id}: ${user.name}`);
|
|
2599
|
+
* }
|
|
2600
|
+
* ```
|
|
2601
|
+
*/
|
|
2602
|
+
getUsers(): User[];
|
|
2603
|
+
/**
|
|
2604
|
+
* Checks if a user exists
|
|
2605
|
+
*
|
|
2606
|
+
* @param id - User ID (string)
|
|
2607
|
+
* @returns true if user exists
|
|
2608
|
+
*
|
|
2609
|
+
* @example
|
|
2610
|
+
* ```typescript
|
|
2611
|
+
* if (engine.hasUser("user1")) {
|
|
2612
|
+
* console.log("User exists");
|
|
2613
|
+
* }
|
|
2614
|
+
* ```
|
|
2615
|
+
*/
|
|
2616
|
+
hasUser(id: string): boolean;
|
|
2617
|
+
/**
|
|
2618
|
+
* Removes a user from the engine
|
|
2619
|
+
*
|
|
2620
|
+
* @param id - User ID to remove (string)
|
|
2621
|
+
* @returns true if user was removed, false if not found
|
|
2622
|
+
*
|
|
2623
|
+
* @example
|
|
2624
|
+
* ```typescript
|
|
2625
|
+
* const removed = engine.removeUser("user1");
|
|
2626
|
+
* if (removed) {
|
|
2627
|
+
* console.log("User removed successfully");
|
|
2628
|
+
* }
|
|
2629
|
+
* ```
|
|
2630
|
+
*/
|
|
2631
|
+
removeUser(id: string): boolean;
|
|
2632
|
+
/**
|
|
2633
|
+
* Gets total number of users
|
|
2634
|
+
*
|
|
2635
|
+
* @returns Number of users
|
|
2636
|
+
*
|
|
2637
|
+
* @example
|
|
2638
|
+
* ```typescript
|
|
2639
|
+
* console.log(`${engine.getUserCount()} users connected`);
|
|
2640
|
+
* ```
|
|
2641
|
+
*/
|
|
2642
|
+
getUserCount(): number;
|
|
2643
|
+
/**
|
|
2644
|
+
* Removes all users from the engine
|
|
2645
|
+
*
|
|
2646
|
+
* Useful for complete reset or cleanup before server shutdown
|
|
2647
|
+
*
|
|
2648
|
+
* @example
|
|
2649
|
+
* ```typescript
|
|
2650
|
+
* engine.clearAllUsers(); // All users removed
|
|
2651
|
+
* console.log(engine.getUserCount()); // 0
|
|
2652
|
+
* ```
|
|
2653
|
+
*/
|
|
2654
|
+
clearAllUsers(): void;
|
|
2655
|
+
/**
|
|
2656
|
+
* Sets a color in the palette
|
|
2657
|
+
*
|
|
2658
|
+
* 🎨 RESERVED COLORS:
|
|
2659
|
+
* - ColorIDs 240-254: Standard UI palette (CANNOT be modified)
|
|
2660
|
+
* - ColorID 255: Skip/transparent color (CANNOT be modified)
|
|
2661
|
+
* - ColorIDs 0-239: Free for application use (240 colors available)
|
|
2662
|
+
*
|
|
2663
|
+
* @param colorId - Color ID (0-239 only, 240-255 are reserved)
|
|
2664
|
+
* @param r - Red component (0-255)
|
|
2665
|
+
* @param g - Green component (0-255)
|
|
2666
|
+
* @param b - Blue component (0-255)
|
|
2667
|
+
* @param a - Alpha component (0-255, default: 255 = opaque)
|
|
2668
|
+
* @param e - Emission component (0-255, default: 0 = no emission)
|
|
2669
|
+
* @throws Error if colorId is reserved (240-255) or out of bounds
|
|
2670
|
+
*
|
|
2671
|
+
* @example
|
|
2672
|
+
* ```typescript
|
|
2673
|
+
* // ✅ Set a custom color in free range
|
|
2674
|
+
* engine.setColor(0, 255, 0, 0, 255, 0);
|
|
2675
|
+
*
|
|
2676
|
+
* // ✅ Set a semi-transparent color
|
|
2677
|
+
* engine.setColor(1, 0, 255, 0, 128, 0);
|
|
2678
|
+
*
|
|
2679
|
+
* // ✅ Set an emissive color (bloom/glow)
|
|
2680
|
+
* engine.setColor(2, 0, 255, 255, 255, 255);
|
|
2681
|
+
*
|
|
2682
|
+
* // ❌ ERROR: ColorIDs 240-254 are reserved (UI palette)
|
|
2683
|
+
* // engine.setColor(245, 255, 0, 0); // Throws error
|
|
2684
|
+
*
|
|
2685
|
+
* // ❌ ERROR: ColorID 255 is reserved (skip color)
|
|
2686
|
+
* // engine.setColor(255, 255, 255, 255); // Throws error
|
|
2687
|
+
* ```
|
|
2688
|
+
*/
|
|
2689
|
+
setColor(colorId: number, r: number, g: number, b: number, a?: number, e?: number): void;
|
|
2690
|
+
/**
|
|
2691
|
+
* Register a callback to be notified when palette changes
|
|
2692
|
+
*
|
|
2693
|
+
* Use this to update the renderer when palette is modified via loadPalette() or setColor().
|
|
2694
|
+
*
|
|
2695
|
+
* @param callback - Function called with the new palette
|
|
2696
|
+
*
|
|
2697
|
+
* @example
|
|
2698
|
+
* ```typescript
|
|
2699
|
+
* core.onPaletteChanged((palette) => {
|
|
2700
|
+
* const paletteArray = Array.from(palette.values());
|
|
2701
|
+
* renderer.setPalette(paletteArray);
|
|
2702
|
+
* });
|
|
2703
|
+
* ```
|
|
2704
|
+
*/
|
|
2705
|
+
onPaletteChanged(callback: (palette: Map<number, {
|
|
2706
|
+
r: number;
|
|
2707
|
+
g: number;
|
|
2708
|
+
b: number;
|
|
2709
|
+
a: number;
|
|
2710
|
+
e: number;
|
|
2711
|
+
}>) => void): void;
|
|
2712
|
+
/**
|
|
2713
|
+
* Register a callback to be notified when a bitmap font is loaded.
|
|
2714
|
+
*
|
|
2715
|
+
* Use this to update the renderer when a font is loaded via loadBitmapFontById().
|
|
2716
|
+
*
|
|
2717
|
+
* @param callback - Function called with the fontId
|
|
2718
|
+
*
|
|
2719
|
+
* @example
|
|
2720
|
+
* ```typescript
|
|
2721
|
+
* core.onBitmapFontChanged((fontId) => {
|
|
2722
|
+
* const font = core.getBitmapFont(fontId);
|
|
2723
|
+
* if (font) renderer.uploadFontToGPU(font);
|
|
2724
|
+
* });
|
|
2725
|
+
* ```
|
|
2726
|
+
*/
|
|
2727
|
+
onBitmapFontChanged(callback: (fontId: number) => void): void;
|
|
2728
|
+
/**
|
|
2729
|
+
* Gets a color from the palette
|
|
2730
|
+
*
|
|
2731
|
+
* @param colorId - Color ID (0-255)
|
|
2732
|
+
* @returns RGBA+E color or null if ID doesn't exist
|
|
2733
|
+
*
|
|
2734
|
+
* @example
|
|
2735
|
+
* ```typescript
|
|
2736
|
+
* const color = engine.getColor(16);
|
|
2737
|
+
* if (color) {
|
|
2738
|
+
* console.log(`RGB: ${color.r}, ${color.g}, ${color.b}`);
|
|
2739
|
+
* console.log(`Emission: ${color.e}`);
|
|
2740
|
+
* }
|
|
2741
|
+
* ```
|
|
2742
|
+
*/
|
|
2743
|
+
getColor(colorId: number): {
|
|
2744
|
+
r: number;
|
|
2745
|
+
g: number;
|
|
2746
|
+
b: number;
|
|
2747
|
+
a: number;
|
|
2748
|
+
e: number;
|
|
2749
|
+
} | null;
|
|
2750
|
+
/**
|
|
2751
|
+
* Loads a complete color palette
|
|
2752
|
+
*
|
|
2753
|
+
* Replaces existing colors for the specified IDs.
|
|
2754
|
+
*
|
|
2755
|
+
* 🎨 RESERVED COLORS (automatically forced):
|
|
2756
|
+
* - ColorIDs 240-254: Standard UI palette (will be overridden even if provided)
|
|
2757
|
+
* - ColorID 255: Skip/transparent color (will be overridden even if provided)
|
|
2758
|
+
* - ColorIDs 0-239: Free for application use
|
|
2759
|
+
*
|
|
2760
|
+
* @param colors - Array of colors to load (any ColorIDs 0-255)
|
|
2761
|
+
*
|
|
2762
|
+
* @example
|
|
2763
|
+
* ```typescript
|
|
2764
|
+
* engine.loadPalette([
|
|
2765
|
+
* { colorId: 0, r: 255, g: 0, b: 0, a: 255, e: 0 }, // ✅ Custom color (free range)
|
|
2766
|
+
* { colorId: 1, r: 255, g: 255, b: 255, a: 255, e: 0 }, // ✅ Custom white
|
|
2767
|
+
* { colorId: 2, r: 255, g: 0, b: 0, a: 255, e: 0 }, // ✅ Custom red
|
|
2768
|
+
* { colorId: 3, r: 0, g: 255, b: 255, a: 255, e: 255 }, // ✅ Bright cyan
|
|
2769
|
+
* { colorId: 250, r: 255, g: 0, b: 0, a: 255, e: 0 }, // ⚠️ Will be ignored (reserved)
|
|
2770
|
+
* ]);
|
|
2771
|
+
* // ColorIDs 240-254 and 255 will be forced to standard values
|
|
2772
|
+
* ```
|
|
2773
|
+
*/
|
|
2774
|
+
loadPalette(colors: Array<{
|
|
2775
|
+
colorId: number;
|
|
2776
|
+
r: number;
|
|
2777
|
+
g: number;
|
|
2778
|
+
b: number;
|
|
2779
|
+
a: number;
|
|
2780
|
+
e?: number;
|
|
2781
|
+
}>): void;
|
|
2782
|
+
/**
|
|
2783
|
+
* Gets the entire color palette
|
|
2784
|
+
*
|
|
2785
|
+
* @returns Map of colors by ID
|
|
2786
|
+
*
|
|
2787
|
+
* @example
|
|
2788
|
+
* ```typescript
|
|
2789
|
+
* const palette = engine.getPalette();
|
|
2790
|
+
* palette.forEach((color, id) => {
|
|
2791
|
+
* console.log(`Color ${id}: rgba(${color.r}, ${color.g}, ${color.b}, ${color.a}) emission: ${color.e}`);
|
|
2792
|
+
* });
|
|
2793
|
+
* ```
|
|
2794
|
+
*/
|
|
2795
|
+
getPalette(): Map<number, {
|
|
2796
|
+
r: number;
|
|
2797
|
+
g: number;
|
|
2798
|
+
b: number;
|
|
2799
|
+
a: number;
|
|
2800
|
+
e: number;
|
|
2801
|
+
}>;
|
|
2802
|
+
/**
|
|
2803
|
+
* Resets palette to default VGA colors
|
|
2804
|
+
*
|
|
2805
|
+
* @example
|
|
2806
|
+
* ```typescript
|
|
2807
|
+
* engine.resetPalette(); // Back to VGA 16 colors palette
|
|
2808
|
+
* ```
|
|
2809
|
+
*/
|
|
2810
|
+
resetPalette(): void;
|
|
2811
|
+
/**
|
|
2812
|
+
* Converts a color ID to a CSS rgba() string
|
|
2813
|
+
*
|
|
2814
|
+
* Useful for HTML/Canvas rendering
|
|
2815
|
+
*
|
|
2816
|
+
* @param colorId - Color ID (0-255)
|
|
2817
|
+
* @returns CSS string "rgba(r, g, b, a)" or null if ID doesn't exist
|
|
2818
|
+
*
|
|
2819
|
+
* @example
|
|
2820
|
+
* ```typescript
|
|
2821
|
+
* const cssColor = engine.getColorCSS(16);
|
|
2822
|
+
* if (cssColor) {
|
|
2823
|
+
* ctx.fillStyle = cssColor; // "rgba(255, 0, 0, 1)"
|
|
2824
|
+
* }
|
|
2825
|
+
* ```
|
|
2826
|
+
*/
|
|
2827
|
+
getColorCSS(colorId: number): string | null;
|
|
2828
|
+
/**
|
|
2829
|
+
* Gets all user IDs
|
|
2830
|
+
*
|
|
2831
|
+
* @returns Array of IDs (strings)
|
|
2832
|
+
*
|
|
2833
|
+
* @example
|
|
2834
|
+
* ```typescript
|
|
2835
|
+
* const ids = engine.getUserIds(); // ["user1", "user2", ...]
|
|
2836
|
+
* ```
|
|
2837
|
+
*/
|
|
2838
|
+
getUserIds(): string[];
|
|
2839
|
+
/**
|
|
2840
|
+
* Iterates over all users with a callback
|
|
2841
|
+
*
|
|
2842
|
+
* @param callback - Function called for each user
|
|
2843
|
+
*
|
|
2844
|
+
* @example
|
|
2845
|
+
* ```typescript
|
|
2846
|
+
* engine.forEachUser((user) => {
|
|
2847
|
+
* user.displays.forEach(d => d.clear());
|
|
2848
|
+
* });
|
|
2849
|
+
* ```
|
|
2850
|
+
*/
|
|
2851
|
+
forEachUser(callback: (user: User) => void): void;
|
|
2852
|
+
/**
|
|
2853
|
+
* Filters users according to a predicate
|
|
2854
|
+
*
|
|
2855
|
+
* @param predicate - Filter function
|
|
2856
|
+
* @returns Array of matching users
|
|
2857
|
+
*
|
|
2858
|
+
* @example
|
|
2859
|
+
* ```typescript
|
|
2860
|
+
* const activeUsers = engine.filterUsers(user => user.displays.length > 0);
|
|
2861
|
+
* ```
|
|
2862
|
+
*/
|
|
2863
|
+
filterUsers(predicate: (user: User) => boolean): User[];
|
|
2864
|
+
/**
|
|
2865
|
+
* Finds a user according to a predicate
|
|
2866
|
+
*
|
|
2867
|
+
* @param predicate - Search function
|
|
2868
|
+
* @returns First matching user or undefined
|
|
2869
|
+
*
|
|
2870
|
+
* @example
|
|
2871
|
+
* ```typescript
|
|
2872
|
+
* const alice = engine.findUser(user => user.name === "Alice");
|
|
2873
|
+
* ```
|
|
2874
|
+
*/
|
|
2875
|
+
findUser(predicate: (user: User) => boolean): User | undefined;
|
|
2876
|
+
/**
|
|
2877
|
+
* Gets current tick number
|
|
2878
|
+
*
|
|
2879
|
+
* @returns Current tick number
|
|
2880
|
+
*
|
|
2881
|
+
* @example
|
|
2882
|
+
* ```typescript
|
|
2883
|
+
* console.log(`Current tick: ${engine.getCurrentTick()}`);
|
|
2884
|
+
* ```
|
|
2885
|
+
*/
|
|
2886
|
+
getCurrentTick(): number;
|
|
2887
|
+
/**
|
|
2888
|
+
* Gets CoreStats object to access performance statistics
|
|
2889
|
+
*
|
|
2890
|
+
* @returns The engine's CoreStats instance
|
|
2891
|
+
*
|
|
2892
|
+
* @example
|
|
2893
|
+
* ```typescript
|
|
2894
|
+
* // Enable stats
|
|
2895
|
+
* engine.getStats().setEnabled(true);
|
|
2896
|
+
*
|
|
2897
|
+
* // After a few ticks...
|
|
2898
|
+
* const report = engine.getStats().generateReport(10);
|
|
2899
|
+
* console.log(report);
|
|
2900
|
+
*
|
|
2901
|
+
* // Access averages
|
|
2902
|
+
* const avg = engine.getStats().getAverageStats(100);
|
|
2903
|
+
* console.log(`Avg packet size: ${avg.avgPacketSize} bytes`);
|
|
2904
|
+
* ```
|
|
2905
|
+
*/
|
|
2906
|
+
getStats(): CoreStats;
|
|
2907
|
+
/**
|
|
2908
|
+
* Ends current tick and generates update packets for all users
|
|
2909
|
+
*
|
|
2910
|
+
* This method:
|
|
2911
|
+
* 1. Encodes displays and layers of each user into binary packets
|
|
2912
|
+
* 2. Increments tick counter
|
|
2913
|
+
* 3. Returns a Map with packets ready to send
|
|
2914
|
+
*
|
|
2915
|
+
* Server/client can then send these packets over the network
|
|
2916
|
+
*
|
|
2917
|
+
* @returns Map<userId, packet> - Encoded packets for each user
|
|
2918
|
+
*
|
|
2919
|
+
* @example
|
|
2920
|
+
* ```typescript
|
|
2921
|
+
* const packets = engine.endTick();
|
|
2922
|
+
* packets.forEach((packet, userId) => {
|
|
2923
|
+
* networkSend(userId, packet);
|
|
2924
|
+
* });
|
|
2925
|
+
* ```
|
|
2926
|
+
*/
|
|
2927
|
+
endTick(): Map<string, Uint8Array>;
|
|
2928
|
+
/**
|
|
2929
|
+
* Ends tick and generates SEPARATE packets for static and dynamic layers
|
|
2930
|
+
*
|
|
2931
|
+
* This method allows sending:
|
|
2932
|
+
* - STATIC Layers on a reliable Socket.IO channel (guaranteed delivery)
|
|
2933
|
+
* - DYNAMIC Layers on a volatile Socket.IO channel (can drop packets)
|
|
2934
|
+
*
|
|
2935
|
+
* Optimization: Static layers (background, pattern) must arrive,
|
|
2936
|
+
* but dynamic layers (particles, trail) can skip frames.
|
|
2937
|
+
*
|
|
2938
|
+
* @returns Map<userId, { static: Uint8Array | null, dynamic: Uint8Array | null }>
|
|
2939
|
+
*
|
|
2940
|
+
* @example
|
|
2941
|
+
* ```typescript
|
|
2942
|
+
* const splitPackets = engine.endTickSplit();
|
|
2943
|
+
* splitPackets.forEach(({ static: staticPacket, dynamic: dynamicPacket }, userId) => {
|
|
2944
|
+
* if (staticPacket) {
|
|
2945
|
+
* network.sendToClient(userId, 'update-static', staticPacket); // Reliable
|
|
2946
|
+
* }
|
|
2947
|
+
* if (dynamicPacket) {
|
|
2948
|
+
* network.sendToClientVolatile(userId, 'update-dynamic', dynamicPacket); // Volatile
|
|
2949
|
+
* }
|
|
2950
|
+
* });
|
|
2951
|
+
* ```
|
|
2952
|
+
*/
|
|
2953
|
+
endTickSplit(): Map<string, {
|
|
2954
|
+
static: Uint8Array | null;
|
|
2955
|
+
dynamic: Uint8Array | null;
|
|
2956
|
+
}>;
|
|
2957
|
+
/**
|
|
2958
|
+
* Generates a complete snapshot of a user's state
|
|
2959
|
+
*
|
|
2960
|
+
* Unlike endTick() which generates incremental updates
|
|
2961
|
+
* (dynamic layers + static layers not yet sent), getSnapshot()
|
|
2962
|
+
* encodes ALL layers (static + dynamic), ignoring the
|
|
2963
|
+
* hasSentStatic flag.
|
|
2964
|
+
*
|
|
2965
|
+
* The snapshot represents the complete state at time T, while
|
|
2966
|
+
* updates are cumulative deltas.
|
|
2967
|
+
*
|
|
2968
|
+
* Use cases:
|
|
2969
|
+
* - Initial connection: Send complete state to new client
|
|
2970
|
+
* - Reconnection: Resynchronize client after disconnection
|
|
2971
|
+
* - Spectators: Allow observer to join mid-game
|
|
2972
|
+
* - Save: Capture state for persistence
|
|
2973
|
+
* - Migration: Transfer user to another server
|
|
2974
|
+
* - Replay: Record initial state for replay
|
|
2975
|
+
*
|
|
2976
|
+
* @param userId - User ID
|
|
2977
|
+
* @returns Complete binary packet (Uint8Array) or null if user doesn't exist
|
|
2978
|
+
*
|
|
2979
|
+
* @example
|
|
2980
|
+
* ```typescript
|
|
2981
|
+
* // Initial connection
|
|
2982
|
+
* socket.on('connect', (userId) => {
|
|
2983
|
+
* const snapshot = engine.getSnapshot(userId);
|
|
2984
|
+
* socket.emit('initial-state', snapshot);
|
|
2985
|
+
* });
|
|
2986
|
+
*
|
|
2987
|
+
* // Reconnection after disconnect
|
|
2988
|
+
* socket.on('reconnect', (userId) => {
|
|
2989
|
+
* const snapshot = engine.getSnapshot(userId);
|
|
2990
|
+
* socket.emit('resync-state', snapshot);
|
|
2991
|
+
* });
|
|
2992
|
+
*
|
|
2993
|
+
* // Spectator joining during game
|
|
2994
|
+
* socket.on('spectate', (spectatorId, targetUserId) => {
|
|
2995
|
+
* const snapshot = engine.getSnapshot(targetUserId);
|
|
2996
|
+
* socket.to(spectatorId).emit('spectate-state', snapshot);
|
|
2997
|
+
* });
|
|
2998
|
+
* ```
|
|
2999
|
+
*/
|
|
3000
|
+
getSnapshot(userId: string): Uint8Array | null;
|
|
3001
|
+
/**
|
|
3002
|
+
* Resets tick counter to 0
|
|
3003
|
+
*
|
|
3004
|
+
* Useful for complete reset or starting a new session
|
|
3005
|
+
*
|
|
3006
|
+
* @example
|
|
3007
|
+
* ```typescript
|
|
3008
|
+
* engine.resetTick();
|
|
3009
|
+
* console.log(engine.getCurrentTick()); // 0
|
|
3010
|
+
* ```
|
|
3011
|
+
*/
|
|
3012
|
+
resetTick(): void;
|
|
3013
|
+
/**
|
|
3014
|
+
* Applies a decoded UpdatePacket to a user (CLIENT-SIDE RECONSTRUCTION)
|
|
3015
|
+
*
|
|
3016
|
+
* This method is the main entry point for reconstructing a user's state
|
|
3017
|
+
* on the client side from a packet received from the server.
|
|
3018
|
+
*
|
|
3019
|
+
* It performs:
|
|
3020
|
+
* 1. User validation (must exist)
|
|
3021
|
+
* 2. Update application via user.applyUpdate()
|
|
3022
|
+
* 3. Automatic rasterization in client mode
|
|
3023
|
+
*
|
|
3024
|
+
* IMPORTANT: This method should ONLY be called in CLIENT mode.
|
|
3025
|
+
* The server generates packets via endTick(), the client applies them.
|
|
3026
|
+
*
|
|
3027
|
+
* @param userId - Target user ID
|
|
3028
|
+
* @param packet - Decoded UpdatePacket (via UpdatePacketDecoder)
|
|
3029
|
+
* @returns true if update was applied, false if user doesn't exist
|
|
3030
|
+
*
|
|
3031
|
+
* @example
|
|
3032
|
+
* ```typescript
|
|
3033
|
+
* // Client side (ClientRuntime)
|
|
3034
|
+
* import { UpdatePacketDecoder } from '@utsp/core';
|
|
3035
|
+
*
|
|
3036
|
+
* const decoder = new UpdatePacketDecoder();
|
|
3037
|
+
*
|
|
3038
|
+
* websocket.on('update', (buffer: Uint8Array) => {
|
|
3039
|
+
* // Decode binary packet
|
|
3040
|
+
* const packet = decoder.decode(buffer);
|
|
3041
|
+
*
|
|
3042
|
+
* // Apply to local user
|
|
3043
|
+
* const applied = core.applyUpdatePacket('user1', packet);
|
|
3044
|
+
*
|
|
3045
|
+
* if (applied) {
|
|
3046
|
+
* // Rendering is automatically updated via getRenderState()
|
|
3047
|
+
* console.log(`Update tick ${packet.tick} applied`);
|
|
3048
|
+
* }
|
|
3049
|
+
* });
|
|
3050
|
+
* ```
|
|
3051
|
+
*/
|
|
3052
|
+
applyUpdatePacket(userId: string, packet: UpdatePacket): boolean;
|
|
3053
|
+
/**
|
|
3054
|
+
* Applies a raw UpdatePacket buffer (decodes then applies)
|
|
3055
|
+
*
|
|
3056
|
+
* Convenient version that combines decoding + application in one step.
|
|
3057
|
+
*
|
|
3058
|
+
* @param userId - Target user ID
|
|
3059
|
+
* @param buffer - Binary buffer received from server
|
|
3060
|
+
* @returns true if update was applied, false if user doesn't exist
|
|
3061
|
+
*
|
|
3062
|
+
* @example
|
|
3063
|
+
* ```typescript
|
|
3064
|
+
* // Simplified version for runtime
|
|
3065
|
+
* websocket.on('update', (buffer: Uint8Array) => {
|
|
3066
|
+
* core.applyUpdatePacketBuffer('user1', buffer);
|
|
3067
|
+
* });
|
|
3068
|
+
* ```
|
|
3069
|
+
*/
|
|
3070
|
+
applyUpdatePacketBuffer(userId: string, buffer: Uint8Array): boolean;
|
|
3071
|
+
/**
|
|
3072
|
+
* Applies a LoadPacket received from the server (CLIENT-SIDE)
|
|
3073
|
+
*
|
|
3074
|
+
* This method automatically decodes the binary buffer and applies
|
|
3075
|
+
* the asset to the Core according to its LoadType:
|
|
3076
|
+
* - ColorPalette → loadPalette()
|
|
3077
|
+
* - Sprite → loadUnicolorSprites()
|
|
3078
|
+
* - MulticolorSprite → loadMulticolorSprites()
|
|
3079
|
+
* - BitmapFont → loadBitmapFontById()
|
|
3080
|
+
* - WebFont → loadWebFontById()
|
|
3081
|
+
* - Sound → (TODO: implement audio system)
|
|
3082
|
+
*
|
|
3083
|
+
* @param buffer - Encoded binary buffer received via WebSocket
|
|
3084
|
+
* @returns true if applied successfully, false on error
|
|
3085
|
+
*
|
|
3086
|
+
* @example
|
|
3087
|
+
* ```typescript
|
|
3088
|
+
* // Client side (ClientRuntime)
|
|
3089
|
+
* websocket.on('load', (buffer: Uint8Array) => {
|
|
3090
|
+
* core.applyLoadPacket(buffer);
|
|
3091
|
+
* });
|
|
3092
|
+
* ```
|
|
3093
|
+
*/
|
|
3094
|
+
applyLoadPacket(buffer: Uint8Array): boolean;
|
|
3095
|
+
/**
|
|
3096
|
+
* Generates a LoadPacket for the current color palette (SERVER-SIDE)
|
|
3097
|
+
*
|
|
3098
|
+
* Encodes the complete palette in binary format ready to send to clients.
|
|
3099
|
+
*
|
|
3100
|
+
* @returns Encoded binary buffer (or null if palette empty)
|
|
3101
|
+
*
|
|
3102
|
+
* @example
|
|
3103
|
+
* ```typescript
|
|
3104
|
+
* // Server side
|
|
3105
|
+
* const palettePacket = core.generatePaletteLoadPacket();
|
|
3106
|
+
* if (palettePacket) {
|
|
3107
|
+
* websocket.emit('load', palettePacket);
|
|
3108
|
+
* }
|
|
3109
|
+
* ```
|
|
3110
|
+
*/
|
|
3111
|
+
generatePaletteLoadPacket(): Uint8Array | null;
|
|
3112
|
+
/**
|
|
3113
|
+
* Generates a LoadPacket for all unicolor sprites (SERVER-SIDE)
|
|
3114
|
+
*
|
|
3115
|
+
* @returns Encoded binary buffer (or null if no sprites)
|
|
3116
|
+
*
|
|
3117
|
+
* @example
|
|
3118
|
+
* ```typescript
|
|
3119
|
+
* const spritesPacket = core.generateUnicolorSpritesLoadPacket();
|
|
3120
|
+
* if (spritesPacket) {
|
|
3121
|
+
* websocket.emit('load', spritesPacket);
|
|
3122
|
+
* }
|
|
3123
|
+
* ```
|
|
3124
|
+
*/
|
|
3125
|
+
generateUnicolorSpritesLoadPacket(): Uint8Array | null;
|
|
3126
|
+
/**
|
|
3127
|
+
* Generates a LoadPacket for all multicolor sprites (SERVER-SIDE)
|
|
3128
|
+
*
|
|
3129
|
+
* @returns Encoded binary buffer (or null if no sprites)
|
|
3130
|
+
*
|
|
3131
|
+
* @example
|
|
3132
|
+
* ```typescript
|
|
3133
|
+
* const spritesPacket = core.generateMulticolorSpritesLoadPacket();
|
|
3134
|
+
* if (spritesPacket) {
|
|
3135
|
+
* websocket.emit('load', spritesPacket);
|
|
3136
|
+
* }
|
|
3137
|
+
* ```
|
|
3138
|
+
*/
|
|
3139
|
+
generateMulticolorSpritesLoadPacket(): Uint8Array | null;
|
|
3140
|
+
/**
|
|
3141
|
+
* Generates LoadPackets for all web fonts (SERVER-SIDE)
|
|
3142
|
+
*
|
|
3143
|
+
* Returns an array of buffers (one font = one packet)
|
|
3144
|
+
*
|
|
3145
|
+
* @returns Array of encoded buffers (or empty array if no fonts)
|
|
3146
|
+
*
|
|
3147
|
+
* @example
|
|
3148
|
+
* ```typescript
|
|
3149
|
+
* const fontPackets = core.generateWebFontsLoadPackets();
|
|
3150
|
+
* fontPackets.forEach(packet => {
|
|
3151
|
+
* websocket.emit('load', packet);
|
|
3152
|
+
* });
|
|
3153
|
+
* ```
|
|
3154
|
+
*/
|
|
3155
|
+
generateWebFontsLoadPackets(): Uint8Array[];
|
|
3156
|
+
/**
|
|
3157
|
+
* Generates LoadPackets for all bitmap fonts (SERVER-SIDE)
|
|
3158
|
+
*
|
|
3159
|
+
* Returns an array of buffers (one font = one packet)
|
|
3160
|
+
*
|
|
3161
|
+
* @returns Array of encoded buffers (or empty array if no fonts)
|
|
3162
|
+
*
|
|
3163
|
+
* @example
|
|
3164
|
+
* ```typescript
|
|
3165
|
+
* const fontPackets = core.generateBitmapFontsLoadPackets();
|
|
3166
|
+
* fontPackets.forEach(packet => {
|
|
3167
|
+
* websocket.emit('load', packet);
|
|
3168
|
+
* });
|
|
3169
|
+
* ```
|
|
3170
|
+
*/
|
|
3171
|
+
generateBitmapFontsLoadPackets(): Uint8Array[];
|
|
3172
|
+
/**
|
|
3173
|
+
* Generates ALL LoadPackets (palette + sprites + fonts) (SERVER-SIDE)
|
|
3174
|
+
*
|
|
3175
|
+
* Useful when a client initially connects to send them
|
|
3176
|
+
* all assets at once.
|
|
3177
|
+
*
|
|
3178
|
+
* @returns Array of all encoded buffers ready to send
|
|
3179
|
+
*
|
|
3180
|
+
* @example
|
|
3181
|
+
* ```typescript
|
|
3182
|
+
* // When a new client connects
|
|
3183
|
+
* socket.on('join', (userId) => {
|
|
3184
|
+
* const packets = core.generateAllLoadPackets();
|
|
3185
|
+
* packets.forEach(packet => {
|
|
3186
|
+
* socket.to(userId).emit('load', packet);
|
|
3187
|
+
* });
|
|
3188
|
+
* });
|
|
3189
|
+
* ```
|
|
3190
|
+
*/
|
|
3191
|
+
generateAllLoadPackets(): Uint8Array[];
|
|
3192
|
+
/**
|
|
3193
|
+
* Applies Input Bindings to a user (CLIENT-SIDE)
|
|
3194
|
+
*
|
|
3195
|
+
* This method allows the client to configure input bindings
|
|
3196
|
+
* that it must capture and send back to the server in compressed form.
|
|
3197
|
+
*
|
|
3198
|
+
* @param userId - Target user ID
|
|
3199
|
+
* @param json - JSON string of bindings from user.getInputBindingsLoadPacket()
|
|
3200
|
+
* @returns true if applied successfully, false if user doesn't exist
|
|
3201
|
+
*
|
|
3202
|
+
* @example
|
|
3203
|
+
* ```typescript
|
|
3204
|
+
* // Client side
|
|
3205
|
+
* websocket.on('input-bindings', (json: string) => {
|
|
3206
|
+
* core.applyInputBindingsLoadPacket('user1', json);
|
|
3207
|
+
* });
|
|
3208
|
+
* ```
|
|
3209
|
+
*/
|
|
3210
|
+
applyInputBindingsLoadPacket(userId: string, json: string): boolean;
|
|
3211
|
+
/**
|
|
3212
|
+
* Generates render state for a user
|
|
3213
|
+
*
|
|
3214
|
+
* This method converts a user's displays and orders into a readable
|
|
3215
|
+
* format with CSS colors, useful for:
|
|
3216
|
+
* - Render debugging
|
|
3217
|
+
* - Server-side preview
|
|
3218
|
+
* - Automated tests
|
|
3219
|
+
* - Snapshot generation
|
|
3220
|
+
*
|
|
3221
|
+
* @param userId - User ID
|
|
3222
|
+
* @returns Render state or null if user doesn't exist
|
|
3223
|
+
*
|
|
3224
|
+
* @example
|
|
3225
|
+
* ```typescript
|
|
3226
|
+
* const state = engine.getRenderState("user1");
|
|
3227
|
+
* if (state) {
|
|
3228
|
+
* console.log(`Tick: ${state.tick}`);
|
|
3229
|
+
* for (const display of state.displays) {
|
|
3230
|
+
* console.log(`Display ${display.width}x${display.height}`);
|
|
3231
|
+
* // Display cells
|
|
3232
|
+
* for (let y = 0; y < display.height; y++) {
|
|
3233
|
+
* let line = "";
|
|
3234
|
+
* for (let x = 0; x < display.width; x++) {
|
|
3235
|
+
* const cell = display.cells[y * display.width + x];
|
|
3236
|
+
* line += cell.char;
|
|
3237
|
+
* }
|
|
3238
|
+
* console.log(line);
|
|
3239
|
+
* }
|
|
3240
|
+
* }
|
|
3241
|
+
* }
|
|
3242
|
+
* ```
|
|
3243
|
+
*/
|
|
3244
|
+
getRenderState(userId: string): UserRenderState | null;
|
|
3245
|
+
/**
|
|
3246
|
+
* Generates render state for all users
|
|
3247
|
+
*
|
|
3248
|
+
* @returns Map of render states by userId
|
|
3249
|
+
*
|
|
3250
|
+
* @example
|
|
3251
|
+
* ```typescript
|
|
3252
|
+
* const allStates = engine.getAllRenderStates();
|
|
3253
|
+
* allStates.forEach((state, userId) => {
|
|
3254
|
+
* console.log(`User ${userId}: ${state.displays.length} displays`);
|
|
3255
|
+
* });
|
|
3256
|
+
* ```
|
|
3257
|
+
*/
|
|
3258
|
+
getAllRenderStates(): Map<string, UserRenderState>;
|
|
3259
|
+
/**
|
|
3260
|
+
* Enables or disables statistics collection
|
|
3261
|
+
*
|
|
3262
|
+
* @param enabled - true to enable, false to disable
|
|
3263
|
+
*
|
|
3264
|
+
* @example
|
|
3265
|
+
* ```typescript
|
|
3266
|
+
* engine.enableStats(true);
|
|
3267
|
+
* // ... run game loop ...
|
|
3268
|
+
* const report = engine.getStatsReport();
|
|
3269
|
+
* console.log(report);
|
|
3270
|
+
* ```
|
|
3271
|
+
*/
|
|
3272
|
+
enableStats(enabled: boolean): void;
|
|
3273
|
+
/**
|
|
3274
|
+
* Returns the statistics instance
|
|
3275
|
+
*
|
|
3276
|
+
* @returns The CoreStats object
|
|
3277
|
+
*/
|
|
3278
|
+
getStatsInstance(): CoreStats;
|
|
3279
|
+
/**
|
|
3280
|
+
* Resets statistics for the current tick
|
|
3281
|
+
*
|
|
3282
|
+
* @example
|
|
3283
|
+
* ```typescript
|
|
3284
|
+
* engine.resetStats();
|
|
3285
|
+
* ```
|
|
3286
|
+
*/
|
|
3287
|
+
resetStats(): void;
|
|
3288
|
+
/**
|
|
3289
|
+
* Loads unicolor sprites from a LoadPacket
|
|
3290
|
+
*
|
|
3291
|
+
* Unicolor sprites only store charCode (1 byte per cell).
|
|
3292
|
+
* Colors are applied during rendering via Orders.
|
|
3293
|
+
*
|
|
3294
|
+
* @param loadData - Loading data from a LoadPacket (type 0x02)
|
|
3295
|
+
*
|
|
3296
|
+
* @example
|
|
3297
|
+
* ```typescript
|
|
3298
|
+
* // Load a 4x4 unicolor sprite
|
|
3299
|
+
* engine.loadUnicolorSprites({
|
|
3300
|
+
* sprites: [
|
|
3301
|
+
* {
|
|
3302
|
+
* spriteId: 1,
|
|
3303
|
+
* sizeX: 4,
|
|
3304
|
+
* sizeY: 4,
|
|
3305
|
+
* data: [
|
|
3306
|
+
* 0x2588, 0x2588, 0x2588, 0x2588,
|
|
3307
|
+
* 0x2588, 0x0020, 0x0020, 0x2588,
|
|
3308
|
+
* 0x2588, 0x0020, 0x0020, 0x2588,
|
|
3309
|
+
* 0x2588, 0x2588, 0x2588, 0x2588
|
|
3310
|
+
* ]
|
|
3311
|
+
* }
|
|
3312
|
+
* ]
|
|
3313
|
+
* });
|
|
3314
|
+
* ```
|
|
3315
|
+
*/
|
|
3316
|
+
loadUnicolorSprites(loadData: SpriteLoad): void;
|
|
3317
|
+
/**
|
|
3318
|
+
* Loads multicolor sprites from a LoadPacket
|
|
3319
|
+
*
|
|
3320
|
+
* Multicolor sprites store charCode + fgColorId + bgColorId (3 bytes per cell).
|
|
3321
|
+
* Optimized for sprites with lots of visual detail.
|
|
3322
|
+
*
|
|
3323
|
+
* @param loadData - Loading data from a LoadPacket (type 0x03)
|
|
3324
|
+
*
|
|
3325
|
+
* @example
|
|
3326
|
+
* ```typescript
|
|
3327
|
+
* // Load a 2x2 multicolor sprite
|
|
3328
|
+
* engine.loadMulticolorSprites({
|
|
3329
|
+
* sprites: [
|
|
3330
|
+
* {
|
|
3331
|
+
* spriteId: 10,
|
|
3332
|
+
* sizeX: 2,
|
|
3333
|
+
* sizeY: 2,
|
|
3334
|
+
* data: [
|
|
3335
|
+
* { charCode: 0x2588, fgColorId: 12, bgColorId: 0 },
|
|
3336
|
+
* { charCode: 0x2588, fgColorId: 14, bgColorId: 0 },
|
|
3337
|
+
* { charCode: 0x2588, fgColorId: 14, bgColorId: 0 },
|
|
3338
|
+
* { charCode: 0x2588, fgColorId: 12, bgColorId: 0 }
|
|
3339
|
+
* ]
|
|
3340
|
+
* }
|
|
3341
|
+
* ]
|
|
3342
|
+
* });
|
|
3343
|
+
* ```
|
|
3344
|
+
*/
|
|
3345
|
+
loadMulticolorSprites(loadData: MulticolorSpriteLoad): void;
|
|
3346
|
+
/**
|
|
3347
|
+
* Unloads a unicolor sprite from memory
|
|
3348
|
+
*
|
|
3349
|
+
* @param spriteId - ID of the sprite to unload
|
|
3350
|
+
* @returns true if sprite was found and removed, false otherwise
|
|
3351
|
+
*
|
|
3352
|
+
* @example
|
|
3353
|
+
* ```typescript
|
|
3354
|
+
* const removed = engine.unloadUnicolorSprite(1);
|
|
3355
|
+
* if (removed) {
|
|
3356
|
+
* console.log("Sprite 1 unloaded");
|
|
3357
|
+
* }
|
|
3358
|
+
* ```
|
|
3359
|
+
*/
|
|
3360
|
+
unloadUnicolorSprite(spriteId: number): boolean;
|
|
3361
|
+
/**
|
|
3362
|
+
* Unloads a multicolor sprite from memory
|
|
3363
|
+
*
|
|
3364
|
+
* @param spriteId - ID of the sprite to unload
|
|
3365
|
+
* @returns true if sprite was found and removed, false otherwise
|
|
3366
|
+
*
|
|
3367
|
+
* @example
|
|
3368
|
+
* ```typescript
|
|
3369
|
+
* const removed = engine.unloadMulticolorSprite(10);
|
|
3370
|
+
* if (removed) {
|
|
3371
|
+
* console.log("Sprite 10 unloaded");
|
|
3372
|
+
* }
|
|
3373
|
+
* ```
|
|
3374
|
+
*/
|
|
3375
|
+
unloadMulticolorSprite(spriteId: number): boolean;
|
|
3376
|
+
/**
|
|
3377
|
+
* Clears all unicolor sprites from memory
|
|
3378
|
+
*
|
|
3379
|
+
* @example
|
|
3380
|
+
* ```typescript
|
|
3381
|
+
* engine.clearUnicolorSprites();
|
|
3382
|
+
* console.log("All unicolor sprites have been unloaded");
|
|
3383
|
+
* ```
|
|
3384
|
+
*/
|
|
3385
|
+
clearUnicolorSprites(): void;
|
|
3386
|
+
/**
|
|
3387
|
+
* Clears all multicolor sprites from memory
|
|
3388
|
+
*
|
|
3389
|
+
* @example
|
|
3390
|
+
* ```typescript
|
|
3391
|
+
* engine.clearMulticolorSprites();
|
|
3392
|
+
* console.log("All multicolor sprites have been unloaded");
|
|
3393
|
+
* ```
|
|
3394
|
+
*/
|
|
3395
|
+
clearMulticolorSprites(): void;
|
|
3396
|
+
/**
|
|
3397
|
+
* Clears all sprites (unicolor and multicolor)
|
|
3398
|
+
*
|
|
3399
|
+
* @example
|
|
3400
|
+
* ```typescript
|
|
3401
|
+
* engine.clearAllSprites();
|
|
3402
|
+
* console.log("All sprites have been unloaded");
|
|
3403
|
+
* ```
|
|
3404
|
+
*/
|
|
3405
|
+
clearAllSprites(): void;
|
|
3406
|
+
/**
|
|
3407
|
+
* Counts the number of loaded unicolor sprites
|
|
3408
|
+
*
|
|
3409
|
+
* @returns Number of unicolor sprites in memory
|
|
3410
|
+
*
|
|
3411
|
+
* @example
|
|
3412
|
+
* ```typescript
|
|
3413
|
+
* const count = engine.getUnicolorSpriteCount();
|
|
3414
|
+
* console.log(`${count} unicolor sprites loaded`);
|
|
3415
|
+
* ```
|
|
3416
|
+
*/
|
|
3417
|
+
getUnicolorSpriteCount(): number;
|
|
3418
|
+
/**
|
|
3419
|
+
* Counts the number of loaded multicolor sprites
|
|
3420
|
+
*
|
|
3421
|
+
* @returns Number of multicolor sprites in memory
|
|
3422
|
+
*
|
|
3423
|
+
* @example
|
|
3424
|
+
* ```typescript
|
|
3425
|
+
* const count = engine.getMulticolorSpriteCount();
|
|
3426
|
+
* console.log(`${count} multicolor sprites loaded`);
|
|
3427
|
+
* ```
|
|
3428
|
+
*/
|
|
3429
|
+
getMulticolorSpriteCount(): number;
|
|
3430
|
+
/**
|
|
3431
|
+
* Counts total number of loaded sprites (unicolor + multicolor)
|
|
3432
|
+
*
|
|
3433
|
+
* @returns Total number of sprites in memory
|
|
3434
|
+
*
|
|
3435
|
+
* @example
|
|
3436
|
+
* ```typescript
|
|
3437
|
+
* const total = engine.getTotalSpriteCount();
|
|
3438
|
+
* console.log(`${total} sprites total`);
|
|
3439
|
+
* ```
|
|
3440
|
+
*/
|
|
3441
|
+
getTotalSpriteCount(): number;
|
|
3442
|
+
/**
|
|
3443
|
+
* Checks if a unicolor sprite exists
|
|
3444
|
+
*
|
|
3445
|
+
* @param spriteId - ID of the sprite to check
|
|
3446
|
+
* @returns true if sprite exists, false otherwise
|
|
3447
|
+
*
|
|
3448
|
+
* @example
|
|
3449
|
+
* ```typescript
|
|
3450
|
+
* if (engine.hasUnicolorSprite(1)) {
|
|
3451
|
+
* console.log("Sprite 1 available");
|
|
3452
|
+
* }
|
|
3453
|
+
* ```
|
|
3454
|
+
*/
|
|
3455
|
+
hasUnicolorSprite(spriteId: number): boolean;
|
|
3456
|
+
/**
|
|
3457
|
+
* Checks if a multicolor sprite exists
|
|
3458
|
+
*
|
|
3459
|
+
* @param spriteId - ID of the sprite to check
|
|
3460
|
+
* @returns true if sprite exists, false otherwise
|
|
3461
|
+
*
|
|
3462
|
+
* @example
|
|
3463
|
+
* ```typescript
|
|
3464
|
+
* if (engine.hasMulticolorSprite(10)) {
|
|
3465
|
+
* console.log("Sprite 10 available");
|
|
3466
|
+
* }
|
|
3467
|
+
* ```
|
|
3468
|
+
*/
|
|
3469
|
+
hasMulticolorSprite(spriteId: number): boolean;
|
|
3470
|
+
/**
|
|
3471
|
+
* Gets the sprite registry (for rasterizer only)
|
|
3472
|
+
* @internal
|
|
3473
|
+
*/
|
|
3474
|
+
getSpriteRegistry(): SpriteRegistry;
|
|
3475
|
+
/**
|
|
3476
|
+
* Loads the default web font (Courier New, 16px, monospace)
|
|
3477
|
+
*
|
|
3478
|
+
* This font is loaded automatically during engine initialization.
|
|
3479
|
+
* It uses fontId 0 (reserved for the default font).
|
|
3480
|
+
*
|
|
3481
|
+
* @private
|
|
3482
|
+
*/
|
|
3483
|
+
private loadDefaultWebFont;
|
|
3484
|
+
/**
|
|
3485
|
+
* Loads a web font into the registry
|
|
3486
|
+
*
|
|
3487
|
+
* Web fonts use the CSS system for rendering (fontFamily, fontSize, etc.)
|
|
3488
|
+
* FontID 0 is reserved for the default font.
|
|
3489
|
+
*
|
|
3490
|
+
* @param font - WebFont instance to load
|
|
3491
|
+
* @throws Error if fontId is already in use
|
|
3492
|
+
*
|
|
3493
|
+
* @example
|
|
3494
|
+
* ```typescript
|
|
3495
|
+
* const customFont = new WebFont(1, {
|
|
3496
|
+
* fontFamily: "Arial",
|
|
3497
|
+
* fontSize: 20,
|
|
3498
|
+
* fontWeight: "bold"
|
|
3499
|
+
* });
|
|
3500
|
+
* engine.loadWebFont(customFont);
|
|
3501
|
+
* ```
|
|
3502
|
+
*/
|
|
3503
|
+
loadWebFont(font: WebFont): void;
|
|
3504
|
+
/**
|
|
3505
|
+
* Gets a web font by its ID
|
|
3506
|
+
*
|
|
3507
|
+
* @param fontId - Font ID (0-255)
|
|
3508
|
+
* @returns The WebFont instance or null if not found
|
|
3509
|
+
*
|
|
3510
|
+
* @example
|
|
3511
|
+
* ```typescript
|
|
3512
|
+
* const font = engine.getWebFont(1);
|
|
3513
|
+
* if (font) {
|
|
3514
|
+
* console.log(font.toCSS());
|
|
3515
|
+
* }
|
|
3516
|
+
* ```
|
|
3517
|
+
*/
|
|
3518
|
+
getWebFont(fontId: number): WebFont | null;
|
|
3519
|
+
/**
|
|
3520
|
+
* Checks if a web font exists
|
|
3521
|
+
*
|
|
3522
|
+
* @param fontId - Font ID (0-255)
|
|
3523
|
+
* @returns true if font exists
|
|
3524
|
+
*
|
|
3525
|
+
* @example
|
|
3526
|
+
* ```typescript
|
|
3527
|
+
* if (engine.hasWebFont(1)) {
|
|
3528
|
+
* console.log("Font 1 is loaded");
|
|
3529
|
+
* }
|
|
3530
|
+
* ```
|
|
3531
|
+
*/
|
|
3532
|
+
hasWebFont(fontId: number): boolean;
|
|
3533
|
+
/**
|
|
3534
|
+
* Unloads a web font from the registry
|
|
3535
|
+
*
|
|
3536
|
+
* Note: Cannot unload the default font (fontId 0)
|
|
3537
|
+
*
|
|
3538
|
+
* @param fontId - Font ID to unload (1-255)
|
|
3539
|
+
* @returns true if font was unloaded
|
|
3540
|
+
* @throws Error if attempting to unload default font (fontId 0)
|
|
3541
|
+
*
|
|
3542
|
+
* @example
|
|
3543
|
+
* ```typescript
|
|
3544
|
+
* const removed = engine.unloadWebFont(1);
|
|
3545
|
+
* if (removed) {
|
|
3546
|
+
* console.log("Font 1 unloaded");
|
|
3547
|
+
* }
|
|
3548
|
+
* ```
|
|
3549
|
+
*/
|
|
3550
|
+
unloadWebFont(fontId: number): boolean;
|
|
3551
|
+
/**
|
|
3552
|
+
* Clears all web fonts (except default font)
|
|
3553
|
+
*
|
|
3554
|
+
* @example
|
|
3555
|
+
* ```typescript
|
|
3556
|
+
* engine.clearWebFonts();
|
|
3557
|
+
* console.log("All custom web fonts cleared");
|
|
3558
|
+
* ```
|
|
3559
|
+
*/
|
|
3560
|
+
clearWebFonts(): void;
|
|
3561
|
+
/**
|
|
3562
|
+
* Sets the active web font
|
|
3563
|
+
*
|
|
3564
|
+
* The active font is used by default for character rendering.
|
|
3565
|
+
*
|
|
3566
|
+
* @param fontId - Font ID to activate (0-255)
|
|
3567
|
+
* @throws Error if font doesn't exist
|
|
3568
|
+
*
|
|
3569
|
+
* @example
|
|
3570
|
+
* ```typescript
|
|
3571
|
+
* engine.setActiveWebFont(1);
|
|
3572
|
+
* console.log(`Active font: ${engine.getActiveWebFontId()}`);
|
|
3573
|
+
* ```
|
|
3574
|
+
*/
|
|
3575
|
+
setActiveWebFont(fontId: number): void;
|
|
3576
|
+
/**
|
|
3577
|
+
* Gets the active web font ID
|
|
3578
|
+
*
|
|
3579
|
+
* @returns Active font ID (0-255)
|
|
3580
|
+
*
|
|
3581
|
+
* @example
|
|
3582
|
+
* ```typescript
|
|
3583
|
+
* const activeFontId = engine.getActiveWebFontId();
|
|
3584
|
+
* console.log(`Current font: ${activeFontId}`);
|
|
3585
|
+
* ```
|
|
3586
|
+
*/
|
|
3587
|
+
getActiveWebFontId(): number;
|
|
3588
|
+
/**
|
|
3589
|
+
* Gets the active web font
|
|
3590
|
+
*
|
|
3591
|
+
* @returns The active WebFont instance
|
|
3592
|
+
*
|
|
3593
|
+
* @example
|
|
3594
|
+
* ```typescript
|
|
3595
|
+
* const activeFont = engine.getActiveWebFont();
|
|
3596
|
+
* console.log(activeFont.toCSS());
|
|
3597
|
+
* ```
|
|
3598
|
+
*/
|
|
3599
|
+
getActiveWebFont(): WebFont;
|
|
3600
|
+
/**
|
|
3601
|
+
* Counts the number of loaded web fonts
|
|
3602
|
+
*
|
|
3603
|
+
* @returns Number of web fonts in memory
|
|
3604
|
+
*
|
|
3605
|
+
* @example
|
|
3606
|
+
* ```typescript
|
|
3607
|
+
* const count = engine.getWebFontCount();
|
|
3608
|
+
* console.log(`${count} web fonts loaded`);
|
|
3609
|
+
* ```
|
|
3610
|
+
*/
|
|
3611
|
+
getWebFontCount(): number;
|
|
3612
|
+
/**
|
|
3613
|
+
* Gets all loaded web font IDs
|
|
3614
|
+
*
|
|
3615
|
+
* @returns Array of fontIds (0-255)
|
|
3616
|
+
*
|
|
3617
|
+
* @example
|
|
3618
|
+
* ```typescript
|
|
3619
|
+
* const fontIds = engine.getWebFontIds();
|
|
3620
|
+
* console.log(`Loaded fonts: ${fontIds.join(", ")}`);
|
|
3621
|
+
* ```
|
|
3622
|
+
*/
|
|
3623
|
+
getWebFontIds(): number[];
|
|
3624
|
+
/**
|
|
3625
|
+
* Gets the web font registry
|
|
3626
|
+
*
|
|
3627
|
+
* @returns WebFontRegistry instance
|
|
3628
|
+
*
|
|
3629
|
+
* @example
|
|
3630
|
+
* ```typescript
|
|
3631
|
+
* const registry = engine.getWebFontRegistry();
|
|
3632
|
+
* console.log(`Total fonts: ${registry.getFontCount()}`);
|
|
3633
|
+
* ```
|
|
3634
|
+
*/
|
|
3635
|
+
getWebFontRegistry(): WebFontRegistry;
|
|
3636
|
+
/**
|
|
3637
|
+
* Gets the bitmap font registry
|
|
3638
|
+
*
|
|
3639
|
+
* @returns BitmapFontRegistry instance
|
|
3640
|
+
*
|
|
3641
|
+
* @example
|
|
3642
|
+
* ```typescript
|
|
3643
|
+
* const registry = engine.getBitmapFontRegistry();
|
|
3644
|
+
* console.log(`Total fonts: ${registry.getFontCount()}`);
|
|
3645
|
+
* ```
|
|
3646
|
+
*/
|
|
3647
|
+
getBitmapFontRegistry(): BitmapFontRegistry;
|
|
3648
|
+
/**
|
|
3649
|
+
* Loads a web font directly with its ID and configuration
|
|
3650
|
+
*
|
|
3651
|
+
* Simplified method that creates and loads the font in one step.
|
|
3652
|
+
*
|
|
3653
|
+
* @param fontId - Unique font ID (0-255, 0 reserved for default font)
|
|
3654
|
+
* @param config - Web font configuration
|
|
3655
|
+
* @throws Error if fontId is already in use
|
|
3656
|
+
*
|
|
3657
|
+
* @example
|
|
3658
|
+
* ```typescript
|
|
3659
|
+
* // Load a custom font
|
|
3660
|
+
* engine.loadWebFontById(1, {
|
|
3661
|
+
* fontFamily: "Arial",
|
|
3662
|
+
* fontSize: 20,
|
|
3663
|
+
* fontWeight: "bold"
|
|
3664
|
+
* });
|
|
3665
|
+
*
|
|
3666
|
+
* // Load a monospace font
|
|
3667
|
+
* engine.loadWebFontById(2, {
|
|
3668
|
+
* fontFamily: "Consolas",
|
|
3669
|
+
* fontSize: 16,
|
|
3670
|
+
* charSpacing: 2
|
|
3671
|
+
* });
|
|
3672
|
+
* ```
|
|
3673
|
+
*/
|
|
3674
|
+
loadWebFontById(fontId: number, config: WebFontConfig): void;
|
|
3675
|
+
/**
|
|
3676
|
+
* Loads a bitmap font directly with its ID and configuration
|
|
3677
|
+
*
|
|
3678
|
+
* Simplified method that loads the bitmap font in one step.
|
|
3679
|
+
*
|
|
3680
|
+
* @param fontId - Unique font ID (0-255)
|
|
3681
|
+
* @param config - Bitmap font configuration (dimensions + glyphs)
|
|
3682
|
+
* @throws Error if fontId is already in use
|
|
3683
|
+
*
|
|
3684
|
+
* @example
|
|
3685
|
+
* ```typescript
|
|
3686
|
+
* import { createASCII8x8FontLoad } from "utsp-core";
|
|
3687
|
+
*
|
|
3688
|
+
* // Load the ASCII 8×8 font
|
|
3689
|
+
* const fontLoad = createASCII8x8FontLoad(1);
|
|
3690
|
+
* engine.loadBitmapFontById(1, fontLoad.fontConfig);
|
|
3691
|
+
*
|
|
3692
|
+
* // Load a custom bitmap font
|
|
3693
|
+
* engine.loadBitmapFontById(10, {
|
|
3694
|
+
* charWidth: 16,
|
|
3695
|
+
* charHeight: 16,
|
|
3696
|
+
* glyphs: new Map([
|
|
3697
|
+
* [65, new Uint8Array([...])], // 'A'
|
|
3698
|
+
* [66, new Uint8Array([...])], // 'B'
|
|
3699
|
+
* ])
|
|
3700
|
+
* });
|
|
3701
|
+
* ```
|
|
3702
|
+
*/
|
|
3703
|
+
loadBitmapFontById(fontId: number, config: BitmapFontConfig): void;
|
|
3704
|
+
/**
|
|
3705
|
+
* Gets a bitmap font by its ID
|
|
3706
|
+
*
|
|
3707
|
+
* @param fontId - Font ID (0-255)
|
|
3708
|
+
* @returns The BitmapFont instance or null if not found
|
|
3709
|
+
*
|
|
3710
|
+
* @example
|
|
3711
|
+
* ```typescript
|
|
3712
|
+
* const font = engine.getBitmapFont(1);
|
|
3713
|
+
* if (font) {
|
|
3714
|
+
* console.log(`Font dimensions: ${font.getCharWidth()}×${font.getCharHeight()}`);
|
|
3715
|
+
* console.log(`Glyphs: ${font.getGlyphCount()}`);
|
|
3716
|
+
* }
|
|
3717
|
+
* ```
|
|
3718
|
+
*/
|
|
3719
|
+
getBitmapFont(fontId: number): BitmapFont | null;
|
|
3720
|
+
/**
|
|
3721
|
+
* Checks if a bitmap font exists
|
|
3722
|
+
*
|
|
3723
|
+
* @param fontId - Font ID (0-255)
|
|
3724
|
+
* @returns true if font exists
|
|
3725
|
+
*
|
|
3726
|
+
* @example
|
|
3727
|
+
* ```typescript
|
|
3728
|
+
* if (engine.hasBitmapFont(1)) {
|
|
3729
|
+
* console.log("Font 1 is loaded");
|
|
3730
|
+
* }
|
|
3731
|
+
* ```
|
|
3732
|
+
*/
|
|
3733
|
+
hasBitmapFont(fontId: number): boolean;
|
|
3734
|
+
/**
|
|
3735
|
+
* Unloads a bitmap font from the registry
|
|
3736
|
+
*
|
|
3737
|
+
* @param fontId - Font ID to unload (0-255)
|
|
3738
|
+
* @returns true if font was unloaded
|
|
3739
|
+
*
|
|
3740
|
+
* @example
|
|
3741
|
+
* ```typescript
|
|
3742
|
+
* const removed = engine.unloadBitmapFont(1);
|
|
3743
|
+
* if (removed) {
|
|
3744
|
+
* console.log("Font 1 unloaded");
|
|
3745
|
+
* }
|
|
3746
|
+
* ```
|
|
3747
|
+
*/
|
|
3748
|
+
unloadBitmapFont(fontId: number): boolean;
|
|
3749
|
+
/**
|
|
3750
|
+
* Clears all bitmap fonts
|
|
3751
|
+
*
|
|
3752
|
+
* @example
|
|
3753
|
+
* ```typescript
|
|
3754
|
+
* engine.clearBitmapFonts();
|
|
3755
|
+
* console.log("All bitmap fonts cleared");
|
|
3756
|
+
* ```
|
|
3757
|
+
*/
|
|
3758
|
+
clearBitmapFonts(): void;
|
|
3759
|
+
/**
|
|
3760
|
+
* Counts the number of loaded bitmap fonts
|
|
3761
|
+
*
|
|
3762
|
+
* @returns Number of bitmap fonts in memory
|
|
3763
|
+
*
|
|
3764
|
+
* @example
|
|
3765
|
+
* ```typescript
|
|
3766
|
+
* const count = engine.getBitmapFontCount();
|
|
3767
|
+
* console.log(`${count} bitmap fonts loaded`);
|
|
3768
|
+
* ```
|
|
3769
|
+
*/
|
|
3770
|
+
getBitmapFontCount(): number;
|
|
3771
|
+
/**
|
|
3772
|
+
* Gets all loaded bitmap font IDs
|
|
3773
|
+
*
|
|
3774
|
+
* @returns Array of fontIds (0-255)
|
|
3775
|
+
*
|
|
3776
|
+
* @example
|
|
3777
|
+
* ```typescript
|
|
3778
|
+
* const fontIds = engine.getBitmapFontIds();
|
|
3779
|
+
* console.log(`Loaded bitmap fonts: ${fontIds.join(", ")}`);
|
|
3780
|
+
* ```
|
|
3781
|
+
*/
|
|
3782
|
+
getBitmapFontIds(): number[];
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3785
|
+
/**
|
|
3786
|
+
* ASCII 8×8 Bitmap Font (Extended - IBM CP437)
|
|
3787
|
+
* Complete character set including:
|
|
3788
|
+
* - ASCII printable characters (32-126)
|
|
3789
|
+
* - Extended ASCII box drawing and blocks (128-255)
|
|
3790
|
+
*
|
|
3791
|
+
* Each character is 8 pixels wide by 8 pixels tall
|
|
3792
|
+
* 1 bit per pixel, packed into 8 bytes per character
|
|
3793
|
+
*
|
|
3794
|
+
* Box drawing characters support:
|
|
3795
|
+
* - Single line borders: ┌ ─ ┐ │ └ ┘ ├ ┤ ┬ ┴ ┼
|
|
3796
|
+
* - Double line borders: ╔ ═ ╗ ║ ╚ ╝ ╠ ╣ ╦ ╩ ╬
|
|
3797
|
+
* - Block characters: █ ▓ ▒ ░ ▀ ▄ ▌ ▐
|
|
3798
|
+
*/
|
|
3799
|
+
/**
|
|
3800
|
+
* 8×8 bitmap font data
|
|
3801
|
+
* Key: ASCII/Extended ASCII character code (32-126, 176-223)
|
|
3802
|
+
* Value: 8 bytes representing the character bitmap
|
|
3803
|
+
*/
|
|
3804
|
+
declare const ASCII_8X8_FONT: Map<number, Uint8Array>;
|
|
3805
|
+
/**
|
|
3806
|
+
* Get the bitmap data for a specific ASCII character
|
|
3807
|
+
* @param charCode ASCII character code (32-126) or Extended ASCII (176-223)
|
|
3808
|
+
* @returns 8-byte bitmap or undefined if character not found
|
|
3809
|
+
*/
|
|
3810
|
+
declare function getCharBitmap(charCode: number): Uint8Array | undefined;
|
|
3811
|
+
/**
|
|
3812
|
+
* Check if a character has a bitmap defined
|
|
3813
|
+
* @param charCode ASCII character code
|
|
3814
|
+
* @returns true if character is defined
|
|
3815
|
+
*/
|
|
3816
|
+
declare function hasChar(charCode: number): boolean;
|
|
3817
|
+
/**
|
|
3818
|
+
* Get all available character codes
|
|
3819
|
+
* @returns Array of ASCII codes (32-126) and Extended ASCII (176-223)
|
|
3820
|
+
*/
|
|
3821
|
+
declare function getAllCharCodes(): number[];
|
|
3822
|
+
/**
|
|
3823
|
+
* Create a BitmapFontLoad packet for the complete ASCII font
|
|
3824
|
+
* @param fontId Font identifier (0-255)
|
|
3825
|
+
* @returns BitmapFontLoad object ready for encoding
|
|
3826
|
+
*/
|
|
3827
|
+
declare function createASCII8x8FontLoad(fontId: number): {
|
|
3828
|
+
loadType: number;
|
|
3829
|
+
fontId: number;
|
|
3830
|
+
width: number;
|
|
3831
|
+
height: number;
|
|
3832
|
+
cellWidth: number;
|
|
3833
|
+
cellHeight: number;
|
|
3834
|
+
characters: Array<{
|
|
3835
|
+
charCode: number;
|
|
3836
|
+
bitmap: Uint8Array;
|
|
3837
|
+
}>;
|
|
3838
|
+
};
|
|
3839
|
+
/**
|
|
3840
|
+
* Get BitmapFontConfig for the complete ASCII 8×8 font
|
|
3841
|
+
* This is a convenience function to get the config directly
|
|
3842
|
+
* for use with UTSPCore.loadBitmapFontById()
|
|
3843
|
+
* @returns BitmapFontConfig ready to use
|
|
3844
|
+
*/
|
|
3845
|
+
declare function getASCII8x8FontConfig(): {
|
|
3846
|
+
charWidth: number;
|
|
3847
|
+
charHeight: number;
|
|
3848
|
+
glyphs: Map<number, Uint8Array>;
|
|
3849
|
+
};
|
|
3850
|
+
|
|
3851
|
+
/**
|
|
3852
|
+
* CompressedInputPacket - Ultra-compact binary format for inputs (V3)
|
|
3853
|
+
*
|
|
3854
|
+
* Architecture:
|
|
3855
|
+
* - CLIENT: Evaluates sources → Compresses → Sends
|
|
3856
|
+
* - SERVER: Receives → Decompresses → Stores in axes/buttons Maps
|
|
3857
|
+
*
|
|
3858
|
+
* MINIMALIST Format (V3):
|
|
3859
|
+
* ┌────────┬───────────┬─────────────┬────────┬──────────┐
|
|
3860
|
+
* │ Tick │ Axes │ Buttons │ Mouse │ Flags │
|
|
3861
|
+
* │ 8 bytes│ N bytes │ M bytes │ 3 bytes│ 1 byte │
|
|
3862
|
+
* └────────┴───────────┴─────────────┴────────┴──────────┘
|
|
3863
|
+
*
|
|
3864
|
+
* Tick (8 bytes) : Frame number (uint64, little-endian)
|
|
3865
|
+
* Axes (N bytes) : 1 byte per axis (int8, -127 to +127)
|
|
3866
|
+
* Buttons (M bytes) : Bitpacking (8 buttons per byte, ⌈ButtonCount/8⌉)
|
|
3867
|
+
* Mouse (3 bytes) : displayId (1) + mouseX (1) + mouseY (1)
|
|
3868
|
+
* Flags (1 byte) : Bit 0 = mouseOverDisplay
|
|
3869
|
+
*
|
|
3870
|
+
* Note: axisCount and buttonCount are known in advance via InputBindingRegistry
|
|
3871
|
+
* Example: 5 axes + 12 buttons = 8 + 5 + 2 + 3 + 1 = 19 bytes
|
|
3872
|
+
*/
|
|
3873
|
+
/**
|
|
3874
|
+
* Represents a compressed input on the server side (after decoding)
|
|
3875
|
+
*
|
|
3876
|
+
* This structure contains already decompressed values:
|
|
3877
|
+
* - Axes: float between -1.0 and +1.0
|
|
3878
|
+
* - Buttons: boolean
|
|
3879
|
+
* - Mouse: position + display + flags
|
|
3880
|
+
* - TextInputs: array of key strings for text input (e.g., ['a', 'Backspace', 'Enter'])
|
|
3881
|
+
*/
|
|
3882
|
+
interface CompressedInputPacket {
|
|
3883
|
+
/** Frame number (tick) - uint64 */
|
|
3884
|
+
tick: bigint;
|
|
3885
|
+
/** Axis values (bindingId → value between -1.0 and +1.0) */
|
|
3886
|
+
axes: Map<number, number>;
|
|
3887
|
+
/** Button states (bindingId → pressed) */
|
|
3888
|
+
buttons: Map<number, boolean>;
|
|
3889
|
+
/** ID of the display where the mouse is located (0-255) */
|
|
3890
|
+
displayId: number;
|
|
3891
|
+
/** Mouse X position (0-255) */
|
|
3892
|
+
mouseX: number;
|
|
3893
|
+
/** Mouse Y position (0-255) */
|
|
3894
|
+
mouseY: number;
|
|
3895
|
+
/** Is the mouse over a display? (vs off-display area) */
|
|
3896
|
+
mouseOverDisplay: boolean;
|
|
3897
|
+
/** Text input events (e.g., ['a', 'Backspace', 'Enter']) - for input boxes, chat, etc. */
|
|
3898
|
+
textInputs: string[];
|
|
3899
|
+
}
|
|
3900
|
+
/**
|
|
3901
|
+
* Creates an empty CompressedInputPacket
|
|
3902
|
+
*
|
|
3903
|
+
* @param tick - Frame number (bigint)
|
|
3904
|
+
* @returns An empty packet with default values
|
|
3905
|
+
*/
|
|
3906
|
+
declare function createEmptyCompressedInputPacket(tick?: bigint): CompressedInputPacket;
|
|
3907
|
+
/**
|
|
3908
|
+
* Helper: Encodes a float (-1.0 to +1.0) to int8 (-128 to +127)
|
|
3909
|
+
*
|
|
3910
|
+
* @param value - Value between -1.0 and +1.0
|
|
3911
|
+
* @returns Value between -128 and +127
|
|
3912
|
+
*
|
|
3913
|
+
* @example
|
|
3914
|
+
* ```typescript
|
|
3915
|
+
* encodeAxisToInt8(-1.0) // -127
|
|
3916
|
+
* encodeAxisToInt8(0.0) // 0
|
|
3917
|
+
* encodeAxisToInt8(1.0) // 127
|
|
3918
|
+
* encodeAxisToInt8(-0.5) // -63
|
|
3919
|
+
* ```
|
|
3920
|
+
*/
|
|
3921
|
+
declare function encodeAxisToInt8(value: number): number;
|
|
3922
|
+
/**
|
|
3923
|
+
* Helper: Decodes an int8 (-128 to +127) to float (-1.0 to +1.0)
|
|
3924
|
+
*
|
|
3925
|
+
* @param value - Value between -128 and +127
|
|
3926
|
+
* @returns Value between -1.0 and +1.0
|
|
3927
|
+
*
|
|
3928
|
+
* @example
|
|
3929
|
+
* ```typescript
|
|
3930
|
+
* decodeInt8ToAxis(-127) // -1.0
|
|
3931
|
+
* decodeInt8ToAxis(0) // 0.0
|
|
3932
|
+
* decodeInt8ToAxis(127) // 1.0
|
|
3933
|
+
* decodeInt8ToAxis(-63) // -0.496...
|
|
3934
|
+
* ```
|
|
3935
|
+
*/
|
|
3936
|
+
declare function decodeInt8ToAxis(value: number): number;
|
|
3937
|
+
/**
|
|
3938
|
+
* Helper: Calculates the number of bytes needed for N buttons (bitpacking)
|
|
3939
|
+
*
|
|
3940
|
+
* @param buttonCount - Number of buttons
|
|
3941
|
+
* @returns Number of bytes needed
|
|
3942
|
+
*
|
|
3943
|
+
* @example
|
|
3944
|
+
* ```typescript
|
|
3945
|
+
* getButtonByteCount(0) // 0
|
|
3946
|
+
* getButtonByteCount(7) // 1
|
|
3947
|
+
* getButtonByteCount(8) // 1
|
|
3948
|
+
* getButtonByteCount(9) // 2
|
|
3949
|
+
* getButtonByteCount(16) // 2
|
|
3950
|
+
* getButtonByteCount(17) // 3
|
|
3951
|
+
* ```
|
|
3952
|
+
*/
|
|
3953
|
+
declare function getButtonByteCount(buttonCount: number): number;
|
|
3954
|
+
/**
|
|
3955
|
+
* Calculates the total size of a compressed packet in bytes (format V3)
|
|
3956
|
+
*
|
|
3957
|
+
* @param axisCount - Number of axes
|
|
3958
|
+
* @param buttonCount - Number of buttons
|
|
3959
|
+
* @returns Size in bytes
|
|
3960
|
+
*
|
|
3961
|
+
* @example
|
|
3962
|
+
* ```typescript
|
|
3963
|
+
* getCompressedPacketSize(5, 12) // 8 + 5 + 2 + 4 = 19 bytes
|
|
3964
|
+
* getCompressedPacketSize(0, 0) // 8 + 0 + 0 + 4 = 12 bytes (minimum)
|
|
3965
|
+
* getCompressedPacketSize(2, 3) // 8 + 2 + 1 + 4 = 15 bytes
|
|
3966
|
+
* ```
|
|
3967
|
+
*/
|
|
3968
|
+
declare function getCompressedPacketSize(axisCount: number, buttonCount: number): number;
|
|
3969
|
+
|
|
3970
|
+
/**
|
|
3971
|
+
* CompressedInputEncoder - Encodes inputs in compact binary format
|
|
3972
|
+
*
|
|
3973
|
+
* USED BY CLIENT (utsp-client)
|
|
3974
|
+
*
|
|
3975
|
+
* Workflow:
|
|
3976
|
+
* 1. Client evaluates sources (keyboard + gamepad + touch, etc.)
|
|
3977
|
+
* 2. Client encodes final values in compact binary
|
|
3978
|
+
* 3. Client sends buffer to server via WebSocket
|
|
3979
|
+
*
|
|
3980
|
+
* MINIMALIST V3 Format (without counts):
|
|
3981
|
+
* - Tick: uint64 (8 bytes)
|
|
3982
|
+
* - Axes: float (-1.0 to +1.0) → int8 (-127 to +127) = 1 byte per axis
|
|
3983
|
+
* - Buttons: boolean → bitpacking = 8 buttons per byte
|
|
3984
|
+
* - DisplayId: uint8 (1 byte) = display ID
|
|
3985
|
+
* - Mouse: mouseX/Y (uint8) + flags = 3 bytes
|
|
3986
|
+
*
|
|
3987
|
+
* PREREQUISITE: Client and server must have the SAME bindings defined!
|
|
3988
|
+
*
|
|
3989
|
+
* Example: 5 axes + 12 buttons + mouse = 19 bytes total
|
|
3990
|
+
*/
|
|
3991
|
+
/**
|
|
3992
|
+
* Encodes inputs in compact binary format v3 (CLIENT-SIDE)
|
|
3993
|
+
*
|
|
3994
|
+
* @param tick - Frame number (bigint for uint64)
|
|
3995
|
+
* @param axes - Map of axis values (bindingId → float between -1.0 and +1.0)
|
|
3996
|
+
* @param buttons - Map of button states (bindingId → pressed)
|
|
3997
|
+
* @param displayId - ID of the display where the mouse is located (0-255)
|
|
3998
|
+
* @param mouseX - Mouse X position (0-255)
|
|
3999
|
+
* @param mouseY - Mouse Y position (0-255)
|
|
4000
|
+
* @param mouseOverDisplay - Is the mouse over a display?
|
|
4001
|
+
* @returns Encoded buffer (without counts, minimalist format)
|
|
4002
|
+
*
|
|
4003
|
+
* @example
|
|
4004
|
+
* ```typescript
|
|
4005
|
+
* const axes = new Map([[0, -0.7], [1, 0.5]]);
|
|
4006
|
+
* const buttons = new Map([[0, true], [1, false], [2, true]]);
|
|
4007
|
+
* const buffer = encodeCompressedInput(42n, axes, buttons, 0, 128, 64, true);
|
|
4008
|
+
* // buffer.length = 8 + 2 + 1 + 4 = 15 bytes
|
|
4009
|
+
* ```
|
|
4010
|
+
*/
|
|
4011
|
+
declare function encodeCompressedInput(tick: bigint, axes: Map<number, number>, buttons: Map<number, boolean>, displayId: number, mouseX: number, mouseY: number, mouseOverDisplay: boolean, textInputs?: string[]): Uint8Array;
|
|
4012
|
+
|
|
4013
|
+
/**
|
|
4014
|
+
* CompressedInputDecoder - Decodes inputs from compact binary format
|
|
4015
|
+
*
|
|
4016
|
+
* USED BY SERVER (utsp-core)
|
|
4017
|
+
*
|
|
4018
|
+
* Workflow:
|
|
4019
|
+
* 1. Server receives binary buffer from client via WebSocket
|
|
4020
|
+
* 2. Server decodes values (MINIMALIST V3 format - without counts)
|
|
4021
|
+
* 3. Server stores in user.axes and user.buttons Maps
|
|
4022
|
+
*
|
|
4023
|
+
* MINIMALIST V3 Format (without counts):
|
|
4024
|
+
* - PREREQUISITE: Client and server must have the SAME bindings defined!
|
|
4025
|
+
* - Buffer does NOT contain AxisCount nor ButtonCount
|
|
4026
|
+
* - Server must pass its registry to know expected structure
|
|
4027
|
+
* - Tick: uint64 (8 bytes)
|
|
4028
|
+
* - Axes: int8 (-127 to +127) → float (-1.0 to +1.0)
|
|
4029
|
+
* - Buttons: bitpacking → boolean (8 buttons per byte)
|
|
4030
|
+
* - DisplayId: uint8 (1 byte) = display ID
|
|
4031
|
+
* - Mouse: uint8 → mouseX/Y + flags (mouseOverDisplay)
|
|
4032
|
+
*
|
|
4033
|
+
* Example (2 axes, 3 buttons):
|
|
4034
|
+
* - Tick (8) + Axes (2) + Buttons (1) + DisplayId (1) + Mouse (3) = 15 bytes
|
|
4035
|
+
*/
|
|
4036
|
+
|
|
4037
|
+
/**
|
|
4038
|
+
* Decodes a binary buffer to CompressedInputPacket v3 (SERVER-SIDE)
|
|
4039
|
+
*
|
|
4040
|
+
* MINIMALIST v3 format: buffer does NOT contain counters!
|
|
4041
|
+
* Server MUST pass its registry to know axisCount and buttonCount.
|
|
4042
|
+
*
|
|
4043
|
+
* IMPORTANT: Client and server must have the SAME bindings defined
|
|
4044
|
+
* (same number of axes and buttons, same order after sorting by bindingId).
|
|
4045
|
+
*
|
|
4046
|
+
* @param buffer - Encoded buffer received from client
|
|
4047
|
+
* @param registry - Server registry to know expected structure
|
|
4048
|
+
* @returns Decoded packet with tick (bigint), axes, buttons, displayId, mouse
|
|
4049
|
+
*
|
|
4050
|
+
* @throws Error if buffer is too small or invalid
|
|
4051
|
+
*
|
|
4052
|
+
* @example
|
|
4053
|
+
* ```typescript
|
|
4054
|
+
* const packet = decodeCompressedInput(buffer, serverRegistry);
|
|
4055
|
+
* // packet.tick → 42n (bigint)
|
|
4056
|
+
* // packet.axes.get(0) → -0.7
|
|
4057
|
+
* // packet.buttons.get(0) → true
|
|
4058
|
+
* // packet.displayId → 0
|
|
4059
|
+
* // packet.mouseOverDisplay → true
|
|
4060
|
+
* ```
|
|
4061
|
+
*/
|
|
4062
|
+
declare function decodeCompressedInput(buffer: Uint8Array, registry: InputBindingRegistry): CompressedInputPacket;
|
|
4063
|
+
|
|
4064
|
+
/**
|
|
4065
|
+
* OrderBuilder - Factory to create orders easily and type-safely
|
|
4066
|
+
*
|
|
4067
|
+
* Instead of manually writing complex structures, use these helpers:
|
|
4068
|
+
*
|
|
4069
|
+
* @example Before (verbose and error-prone)
|
|
4070
|
+
* ```typescript
|
|
4071
|
+
* const order = {
|
|
4072
|
+
* type: 0x0a,
|
|
4073
|
+
* shapeType: 0x01,
|
|
4074
|
+
* shapeData: {
|
|
4075
|
+
* posX: 10,
|
|
4076
|
+
* posY: 20,
|
|
4077
|
+
* width: 5,
|
|
4078
|
+
* height: 3,
|
|
4079
|
+
* filled: true,
|
|
4080
|
+
* charCode: 0x31,
|
|
4081
|
+
* bgColorCode: 1,
|
|
4082
|
+
* fgColorCode: 15
|
|
4083
|
+
* }
|
|
4084
|
+
* };
|
|
4085
|
+
* ```
|
|
4086
|
+
*
|
|
4087
|
+
* @example After (simple and type-safe with string support!)
|
|
4088
|
+
* ```typescript
|
|
4089
|
+
* // Both syntaxes work:
|
|
4090
|
+
* const order1 = OrderBuilder.rectangle(10, 20, 5, 3, {
|
|
4091
|
+
* charCode: '1', // ✨ NEW: Use string directly!
|
|
4092
|
+
* bgColor: 1,
|
|
4093
|
+
* fgColor: 15,
|
|
4094
|
+
* filled: true
|
|
4095
|
+
* });
|
|
4096
|
+
*
|
|
4097
|
+
* const order2 = OrderBuilder.char(10, 20, '#', 15, 0); // ✨ String support!
|
|
4098
|
+
* const order3 = OrderBuilder.char(10, 20, 0x23, 15, 0); // Number still works
|
|
4099
|
+
* ```
|
|
4100
|
+
*/
|
|
4101
|
+
|
|
4102
|
+
/**
|
|
4103
|
+
* Common options for graphical orders
|
|
4104
|
+
*/
|
|
4105
|
+
interface ColorOptions {
|
|
4106
|
+
charCode?: string | number;
|
|
4107
|
+
bgColor?: number;
|
|
4108
|
+
fgColor?: number;
|
|
4109
|
+
}
|
|
4110
|
+
/**
|
|
4111
|
+
* OrderBuilder - Static factory to create orders
|
|
4112
|
+
*/
|
|
4113
|
+
declare class OrderBuilder {
|
|
4114
|
+
/**
|
|
4115
|
+
* Convert string or number to 8-bit character code
|
|
4116
|
+
* @param char - Either a string (first character used) or a number (0-255)
|
|
4117
|
+
* @returns 8-bit character code (0-255)
|
|
4118
|
+
* @example
|
|
4119
|
+
* toCharCode('#') // → 0x23 (35)
|
|
4120
|
+
* toCharCode(0x23) // → 0x23 (35)
|
|
4121
|
+
* toCharCode('ABC') // → 0x41 (65, first char only)
|
|
4122
|
+
*/
|
|
4123
|
+
static toCharCode(char: string | number): number;
|
|
4124
|
+
/**
|
|
4125
|
+
* Remove common leading whitespace from multiline strings (dedent)
|
|
4126
|
+
* Useful for template literals that are indented in source code
|
|
4127
|
+
* @param text - Multiline text to dedent
|
|
4128
|
+
* @returns Dedented text
|
|
4129
|
+
* @example
|
|
4130
|
+
* const text = `
|
|
4131
|
+
* Hello
|
|
4132
|
+
* World
|
|
4133
|
+
* `;
|
|
4134
|
+
* dedent(text) // → "Hello\nWorld"
|
|
4135
|
+
*/
|
|
4136
|
+
static dedent(text: string): string;
|
|
4137
|
+
/**
|
|
4138
|
+
* 0x01 - Char: Single character at a position
|
|
4139
|
+
* @param char - Character as string ('#') or charCode (0x23)
|
|
4140
|
+
*/
|
|
4141
|
+
static char(x: number, y: number, char: string | number, fgColor?: number, bgColor?: number): CharOrder;
|
|
4142
|
+
/**
|
|
4143
|
+
* 0x02 - Text: Horizontal character string
|
|
4144
|
+
*/
|
|
4145
|
+
static text(x: number, y: number, text: string, fgColor?: number, bgColor?: number): TextOrder;
|
|
4146
|
+
/**
|
|
4147
|
+
* 0x17 - TextMultiline: Multiple lines of text (\n for line breaks)
|
|
4148
|
+
* Automatically removes common indentation (dedent) for template literals
|
|
4149
|
+
* @example With explicit \n
|
|
4150
|
+
* OrderBuilder.textMultiline(10, 5, 'Hello\nWorld\n!', 15, 0)
|
|
4151
|
+
*
|
|
4152
|
+
* @example With template literal (auto-dedented)
|
|
4153
|
+
* OrderBuilder.textMultiline(10, 5, `
|
|
4154
|
+
* Score: ${score}
|
|
4155
|
+
* Lives: ${lives}
|
|
4156
|
+
* Level: ${level}
|
|
4157
|
+
* `, 15, 0)
|
|
4158
|
+
*/
|
|
4159
|
+
static textMultiline(x: number, y: number, text: string, fgColor?: number, bgColor?: number): TextMultilineOrder;
|
|
4160
|
+
/**
|
|
4161
|
+
* 0x03 - SubFrame: Rectangular area with uniform colors
|
|
4162
|
+
* @param frame - Array of characters as strings or numbers
|
|
4163
|
+
*/
|
|
4164
|
+
static subFrame(x: number, y: number, width: number, height: number, frame: (string | number)[], fgColor?: number, bgColor?: number): SubFrameOrder;
|
|
4165
|
+
/**
|
|
4166
|
+
* 0x04 - SubFrameMultiColor: Rectangular area with per-cell colors
|
|
4167
|
+
* @param frame - Array of cells where charCode can be string or number
|
|
4168
|
+
*/
|
|
4169
|
+
static subFrameMultiColor(x: number, y: number, width: number, height: number, frame: Array<{
|
|
4170
|
+
charCode: string | number;
|
|
4171
|
+
bgColorCode: number;
|
|
4172
|
+
fgColorCode: number;
|
|
4173
|
+
}>): SubFrameMultiColorOrder;
|
|
4174
|
+
/**
|
|
4175
|
+
* 0x05 - FullFrame: Entire layer (256×256) with uniform colors
|
|
4176
|
+
* @param frame - Array of characters as strings or numbers
|
|
4177
|
+
*/
|
|
4178
|
+
static fullFrame(frame: (string | number)[], fgColor?: number, bgColor?: number): FullFrameOrder;
|
|
4179
|
+
/**
|
|
4180
|
+
* 0x06 - FullFrameMultiColor: Entire layer (256×256) with per-cell colors
|
|
4181
|
+
* @param frame - Array of cells where charCode can be string or number
|
|
4182
|
+
*/
|
|
4183
|
+
static fullFrameMultiColor(frame: Array<{
|
|
4184
|
+
charCode: string | number;
|
|
4185
|
+
bgColorCode: number;
|
|
4186
|
+
fgColorCode: number;
|
|
4187
|
+
}>): FullFrameMultiColorOrder;
|
|
4188
|
+
/**
|
|
4189
|
+
* 0x07 - Sprite: Single-color sprite at a position
|
|
4190
|
+
*/
|
|
4191
|
+
static sprite(x: number, y: number, spriteIndex: number, fgColor?: number, bgColor?: number): SpriteOrder;
|
|
4192
|
+
/**
|
|
4193
|
+
* 0x08 - SpriteMultiColor: Multi-color sprite at a position
|
|
4194
|
+
*/
|
|
4195
|
+
static spriteMultiColor(x: number, y: number, spriteIndex: number): SpriteMultiColorOrder;
|
|
4196
|
+
/**
|
|
4197
|
+
* 0x09 - ColorMap: Applies colors without changing characters
|
|
4198
|
+
*/
|
|
4199
|
+
static colorMap(x: number, y: number, width: number, height: number, colorData: Array<{
|
|
4200
|
+
fgColorCode: number;
|
|
4201
|
+
bgColorCode: number;
|
|
4202
|
+
}>): ColorMapOrder;
|
|
4203
|
+
/**
|
|
4204
|
+
* 0x0A - Rectangle Shape
|
|
4205
|
+
* @param options.charCode - Character as string ('█') or charCode (0x2588)
|
|
4206
|
+
*/
|
|
4207
|
+
static rectangle(x: number, y: number, width: number, height: number, options?: {
|
|
4208
|
+
charCode?: string | number;
|
|
4209
|
+
bgColor?: number;
|
|
4210
|
+
fgColor?: number;
|
|
4211
|
+
filled?: boolean;
|
|
4212
|
+
}): ShapeOrder;
|
|
4213
|
+
/**
|
|
4214
|
+
* 0x0A - Circle Shape
|
|
4215
|
+
* @param options.charCode - Character as string ('█') or charCode (0x2588)
|
|
4216
|
+
*/
|
|
4217
|
+
static circle(centerX: number, centerY: number, radius: number, options?: {
|
|
4218
|
+
charCode?: string | number;
|
|
4219
|
+
bgColor?: number;
|
|
4220
|
+
fgColor?: number;
|
|
4221
|
+
filled?: boolean;
|
|
4222
|
+
}): ShapeOrder;
|
|
4223
|
+
/**
|
|
4224
|
+
* 0x0A - Line Shape
|
|
4225
|
+
* @param options.charCode - Character as string ('█') or charCode (0x2588)
|
|
4226
|
+
*/
|
|
4227
|
+
static line(x1: number, y1: number, x2: number, y2: number, options?: {
|
|
4228
|
+
charCode?: string | number;
|
|
4229
|
+
bgColor?: number;
|
|
4230
|
+
fgColor?: number;
|
|
4231
|
+
}): ShapeOrder;
|
|
4232
|
+
/**
|
|
4233
|
+
* 0x0A - Ellipse Shape
|
|
4234
|
+
* @param options.charCode - Character as string ('█') or charCode (0x2588)
|
|
4235
|
+
*/
|
|
4236
|
+
static ellipse(centerX: number, centerY: number, radiusX: number, radiusY: number, options?: {
|
|
4237
|
+
charCode?: string | number;
|
|
4238
|
+
bgColor?: number;
|
|
4239
|
+
fgColor?: number;
|
|
4240
|
+
filled?: boolean;
|
|
4241
|
+
}): ShapeOrder;
|
|
4242
|
+
/**
|
|
4243
|
+
* 0x0A - Triangle Shape
|
|
4244
|
+
* @param options.charCode - Character as string ('█') or charCode (0x2588)
|
|
4245
|
+
*/
|
|
4246
|
+
static triangle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, options?: {
|
|
4247
|
+
charCode?: string | number;
|
|
4248
|
+
bgColor?: number;
|
|
4249
|
+
fgColor?: number;
|
|
4250
|
+
filled?: boolean;
|
|
4251
|
+
}): ShapeOrder;
|
|
4252
|
+
/**
|
|
4253
|
+
* 0x0B - DotCloud: Same character at multiple positions
|
|
4254
|
+
* @param char - Character as string ('#') or charCode (0x23)
|
|
4255
|
+
*/
|
|
4256
|
+
static dotCloud(positions: Array<{
|
|
4257
|
+
posX: number;
|
|
4258
|
+
posY: number;
|
|
4259
|
+
}>, char: string | number, fgColor?: number, bgColor?: number): DotCloudOrder;
|
|
4260
|
+
/**
|
|
4261
|
+
* 0x0C - DotCloudMultiColor: Different characters at multiple positions
|
|
4262
|
+
* @param dots - Array where charCode can be string or number
|
|
4263
|
+
*/
|
|
4264
|
+
static dotCloudMultiColor(dots: Array<{
|
|
4265
|
+
posX: number;
|
|
4266
|
+
posY: number;
|
|
4267
|
+
charCode: string | number;
|
|
4268
|
+
bgColorCode: number;
|
|
4269
|
+
fgColorCode: number;
|
|
4270
|
+
}>): DotCloudMultiColorOrder;
|
|
4271
|
+
/**
|
|
4272
|
+
* 0x11 - Bitmask: Bitpacked presence/absence mask with uniform character
|
|
4273
|
+
* Perfect for ore veins, destructible terrain, collision maps, fog of war
|
|
4274
|
+
* @param mask - Flat array of booleans (row-major order: sizeX × sizeY)
|
|
4275
|
+
* @param char - Character as string ('#') or charCode (0x23)
|
|
4276
|
+
* @param override - true: clear absences (transparent), false: preserve existing cells
|
|
4277
|
+
* @example Create a 3×3 cross pattern
|
|
4278
|
+
* OrderBuilder.bitmask(10, 10, 3, 3, [
|
|
4279
|
+
* false, true, false,
|
|
4280
|
+
* true, true, true,
|
|
4281
|
+
* false, true, false
|
|
4282
|
+
* ], '#', 15, 0, false)
|
|
4283
|
+
*/
|
|
4284
|
+
static bitmask(x: number, y: number, width: number, height: number, mask: boolean[], char: string | number, fgColor?: number, bgColor?: number, override?: boolean): BitmaskOrder;
|
|
4285
|
+
/**
|
|
4286
|
+
* 0x0D - SpriteCloud: Same single-color sprite at multiple positions
|
|
4287
|
+
*/
|
|
4288
|
+
static spriteCloud(spriteIndex: number, positions: Array<{
|
|
4289
|
+
posX: number;
|
|
4290
|
+
posY: number;
|
|
4291
|
+
}>, fgColor?: number, bgColor?: number): SpriteCloudOrder;
|
|
4292
|
+
/**
|
|
4293
|
+
* 0x0E - SpriteCloudMultiColor: Same multi-color sprite at multiple positions
|
|
4294
|
+
*/
|
|
4295
|
+
static spriteCloudMultiColor(spriteIndex: number, positions: Array<{
|
|
4296
|
+
posX: number;
|
|
4297
|
+
posY: number;
|
|
4298
|
+
}>): SpriteCloudMultiColorOrder;
|
|
4299
|
+
/**
|
|
4300
|
+
* 0x0F - SpriteCloudVaried: Different single-color sprites at multiple positions
|
|
4301
|
+
*/
|
|
4302
|
+
static spriteCloudVaried(sprites: Array<{
|
|
4303
|
+
posX: number;
|
|
4304
|
+
posY: number;
|
|
4305
|
+
spriteIndex: number;
|
|
4306
|
+
bgColorCode: number;
|
|
4307
|
+
fgColorCode: number;
|
|
4308
|
+
}>): SpriteCloudVariedOrder;
|
|
4309
|
+
/**
|
|
4310
|
+
* 0x10 - SpriteCloudVariedMultiColor: Different multi-color sprites at multiple positions
|
|
4311
|
+
*/
|
|
4312
|
+
static spriteCloudVariedMultiColor(sprites: Array<{
|
|
4313
|
+
posX: number;
|
|
4314
|
+
posY: number;
|
|
4315
|
+
spriteIndex: number;
|
|
4316
|
+
}>): SpriteCloudVariedMultiColorOrder;
|
|
4317
|
+
/**
|
|
4318
|
+
* 0x13 - Clear: Fills entire layer with a character
|
|
4319
|
+
* @param char - Character as string (' ') or charCode (0x20)
|
|
4320
|
+
*/
|
|
4321
|
+
static clear(char?: string | number, fgColor?: number, bgColor?: number): ClearOrder;
|
|
4322
|
+
/**
|
|
4323
|
+
* 0x14 - FillChar: Fills layer with a repeating pattern
|
|
4324
|
+
* @param pattern - Array of characters as strings or numbers
|
|
4325
|
+
*/
|
|
4326
|
+
static fillChar(patternWidth: number, patternHeight: number, pattern: (string | number)[], fgColor?: number, bgColor?: number): FillCharOrder;
|
|
4327
|
+
/**
|
|
4328
|
+
* 0x15 - FillSprite: Fills layer with a repeating single-color sprite
|
|
4329
|
+
*/
|
|
4330
|
+
static fillSprite(spriteIndex: number, fgColor?: number, bgColor?: number): FillSpriteOrder;
|
|
4331
|
+
/**
|
|
4332
|
+
* 0x16 - FillSpriteMultiColor: Fills layer with a repeating multi-color sprite
|
|
4333
|
+
*/
|
|
4334
|
+
static fillSpriteMultiColor(spriteIndex: number): FillSpriteMultiColorOrder;
|
|
4335
|
+
/**
|
|
4336
|
+
* Helper: Create a rectangle with colored border and different interior
|
|
4337
|
+
* @param borderOptions.charCode - Character as string ('█') or charCode (0x2588)
|
|
4338
|
+
* @param fillOptions.charCode - Character as string ('█') or charCode (0x2588)
|
|
4339
|
+
*/
|
|
4340
|
+
static boxWithBorder(x: number, y: number, width: number, height: number, borderOptions: ColorOptions & {
|
|
4341
|
+
charCode?: string | number;
|
|
4342
|
+
}, fillOptions: ColorOptions & {
|
|
4343
|
+
charCode?: string | number;
|
|
4344
|
+
}): ShapeOrder[];
|
|
4345
|
+
/**
|
|
4346
|
+
* Helper: Create a grid of points
|
|
4347
|
+
* @param options.charCode - Character as string ('+') or charCode (0x2b)
|
|
4348
|
+
*/
|
|
4349
|
+
static grid(startX: number, startY: number, cellWidth: number, cellHeight: number, rows: number, cols: number, options?: ColorOptions): DotCloudOrder;
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
/**
|
|
4353
|
+
* UTSP Protocol Constants
|
|
4354
|
+
* Fixed and minimum sizes for network packets (in bytes)
|
|
4355
|
+
* Shared between encoding and decoding
|
|
4356
|
+
*/
|
|
4357
|
+
/**
|
|
4358
|
+
* Immutable layer size (in cells)
|
|
4359
|
+
* All layers are always 256×256 cells = 65536 cells total
|
|
4360
|
+
*/
|
|
4361
|
+
declare const LAYER_SIZE = 256;
|
|
4362
|
+
declare const LAYER_CELL_COUNT = 65536;
|
|
4363
|
+
/**
|
|
4364
|
+
* Sentinel value to indicate "no color" (transparent)
|
|
4365
|
+
* ColorCode 255 = skip this color (look in following layers)
|
|
4366
|
+
* ColorCodes 0-254 = real colors definable by user
|
|
4367
|
+
*
|
|
4368
|
+
* IMPORTANT NOTE:
|
|
4369
|
+
* - ColorID 255 is RESERVED by the engine and cannot be modified via setColor()
|
|
4370
|
+
* - Palette can contain 255 customizable colors (IDs 0-254)
|
|
4371
|
+
* - Total: 256 possible ColorIDs (0-255) but only 0-254 are usable
|
|
4372
|
+
* - Engine forces ColorID 255 = rgba(0,0,0,0) at startup (transparency)
|
|
4373
|
+
*/
|
|
4374
|
+
declare const COLOR_SKIP = 255;
|
|
4375
|
+
declare const UPDATE_PACKET_HEADER_SIZE = 9;
|
|
4376
|
+
declare const DISPLAY_HEADER_SIZE = 5;
|
|
4377
|
+
declare const LAYER_HEADER_SIZE = 13;
|
|
4378
|
+
declare const CHAR_ORDER_SIZE = 6;
|
|
4379
|
+
declare const TEXT_ORDER_MIN_SIZE = 6;
|
|
4380
|
+
declare const TEXT_MULTILINE_ORDER_MIN_SIZE = 6;
|
|
4381
|
+
declare const SUBFRAME_ORDER_MIN_SIZE = 7;
|
|
4382
|
+
declare const SUBFRAME_MULTICOLOR_ORDER_MIN_SIZE = 5;
|
|
4383
|
+
declare const FULLFRAME_ORDER_MIN_SIZE = 3;
|
|
4384
|
+
declare const FULLFRAME_MULTICOLOR_ORDER_MIN_SIZE = 1;
|
|
4385
|
+
declare const SPRITE_ORDER_SIZE = 6;
|
|
4386
|
+
declare const SPRITE_MULTICOLOR_ORDER_SIZE = 4;
|
|
4387
|
+
declare const COLORMAP_ORDER_MIN_SIZE = 5;
|
|
4388
|
+
declare const SHAPE_ORDER_MIN_SIZE = 2;
|
|
4389
|
+
declare const RECTANGLE_SHAPE_SIZE = 8;
|
|
4390
|
+
declare const CIRCLE_SHAPE_SIZE = 7;
|
|
4391
|
+
declare const LINE_SHAPE_SIZE = 7;
|
|
4392
|
+
declare const ELLIPSE_SHAPE_SIZE = 8;
|
|
4393
|
+
declare const TRIANGLE_SHAPE_SIZE = 10;
|
|
4394
|
+
declare const DOTCLOUD_ORDER_MIN_SIZE = 6;
|
|
4395
|
+
declare const DOTCLOUD_MULTICOLOR_ORDER_MIN_SIZE = 3;
|
|
4396
|
+
declare const BITMASK_ORDER_MIN_SIZE = 9;
|
|
4397
|
+
declare const SPRITECLOUD_ORDER_MIN_SIZE = 6;
|
|
4398
|
+
declare const SPRITECLOUD_MULTICOLOR_ORDER_MIN_SIZE = 4;
|
|
4399
|
+
declare const SPRITECLOUD_VARIED_ORDER_MIN_SIZE = 3;
|
|
4400
|
+
declare const SPRITECLOUD_VARIED_MULTICOLOR_ORDER_MIN_SIZE = 3;
|
|
4401
|
+
declare const CLEAR_ORDER_SIZE = 4;
|
|
4402
|
+
declare const FILLCHAR_ORDER_MIN_SIZE = 5;
|
|
4403
|
+
declare const FILLSPRITE_ORDER_SIZE = 4;
|
|
4404
|
+
declare const FILLSPRITE_MULTICOLOR_ORDER_SIZE = 2;
|
|
4405
|
+
declare const TRIGGERSOUND_ORDER_SIZE = 5;
|
|
4406
|
+
declare const TRIGGERGLOBALSOUND_ORDER_SIZE = 3;
|
|
4407
|
+
|
|
4408
|
+
/**
|
|
4409
|
+
* UTSP Order Types Enumeration
|
|
4410
|
+
*
|
|
4411
|
+
* All 21 order types defined in the UTSP Protocol v0.1
|
|
4412
|
+
* Use these constants instead of raw hexadecimal values for better readability
|
|
4413
|
+
* and type safety.
|
|
4414
|
+
*
|
|
4415
|
+
* @example
|
|
4416
|
+
* ```typescript
|
|
4417
|
+
* import { OrderType } from 'utsp-core';
|
|
4418
|
+
*
|
|
4419
|
+
* // Instead of: type: 0x01
|
|
4420
|
+
* const order = { type: OrderType.Char, posX: 10, posY: 5, ... };
|
|
4421
|
+
* ```
|
|
4422
|
+
*/
|
|
4423
|
+
declare enum OrderType {
|
|
4424
|
+
/**
|
|
4425
|
+
* 0x01 - Char: Renders a single character at a specific position
|
|
4426
|
+
*/
|
|
4427
|
+
Char = 1,
|
|
4428
|
+
/**
|
|
4429
|
+
* 0x02 - Text: Renders a string of characters with uniform colors
|
|
4430
|
+
*/
|
|
4431
|
+
Text = 2,
|
|
4432
|
+
/**
|
|
4433
|
+
* 0x17 - TextMultiline: Renders multiple lines of text (\n for line breaks)
|
|
4434
|
+
*/
|
|
4435
|
+
TextMultiline = 23,
|
|
4436
|
+
/**
|
|
4437
|
+
* 0x03 - SubFrame: Renders a rectangular region with uniform colors
|
|
4438
|
+
*/
|
|
4439
|
+
SubFrame = 3,
|
|
4440
|
+
/**
|
|
4441
|
+
* 0x04 - SubFrameMultiColor: Rectangular region with per-cell colors
|
|
4442
|
+
*/
|
|
4443
|
+
SubFrameMultiColor = 4,
|
|
4444
|
+
/**
|
|
4445
|
+
* 0x05 - FullFrame: Renders entire screen with uniform colors
|
|
4446
|
+
*/
|
|
4447
|
+
FullFrame = 5,
|
|
4448
|
+
/**
|
|
4449
|
+
* 0x06 - FullFrameMultiColor: Entire screen with per-cell colors
|
|
4450
|
+
*/
|
|
4451
|
+
FullFrameMultiColor = 6,
|
|
4452
|
+
/**
|
|
4453
|
+
* 0x07 - Sprite: Renders a preloaded unicolor sprite
|
|
4454
|
+
*/
|
|
4455
|
+
Sprite = 7,
|
|
4456
|
+
/**
|
|
4457
|
+
* 0x08 - SpriteMultiColor: Renders a preloaded multicolor sprite
|
|
4458
|
+
*/
|
|
4459
|
+
SpriteMultiColor = 8,
|
|
4460
|
+
/**
|
|
4461
|
+
* 0x09 - ColorMap: Applies colors to a region without changing characters
|
|
4462
|
+
*/
|
|
4463
|
+
ColorMap = 9,
|
|
4464
|
+
/**
|
|
4465
|
+
* 0x0A - Shape: Renders geometric shapes
|
|
4466
|
+
*/
|
|
4467
|
+
Shape = 10,
|
|
4468
|
+
/**
|
|
4469
|
+
* 0x0B - DotCloud: Same character at multiple positions (up to 65535)
|
|
4470
|
+
*/
|
|
4471
|
+
DotCloud = 11,
|
|
4472
|
+
/**
|
|
4473
|
+
* 0x0C - DotCloudMultiColor: Different characters at multiple positions
|
|
4474
|
+
*/
|
|
4475
|
+
DotCloudMultiColor = 12,
|
|
4476
|
+
/**
|
|
4477
|
+
* 0x0D - SpriteCloud: Same unicolor sprite at multiple positions
|
|
4478
|
+
*/
|
|
4479
|
+
SpriteCloud = 13,
|
|
4480
|
+
/**
|
|
4481
|
+
* 0x0E - SpriteCloudMultiColor: Same multicolor sprite at multiple positions
|
|
4482
|
+
*/
|
|
4483
|
+
SpriteCloudMultiColor = 14,
|
|
4484
|
+
/**
|
|
4485
|
+
* 0x0F - SpriteCloudVaried: Different unicolor sprites at multiple positions
|
|
4486
|
+
*/
|
|
4487
|
+
SpriteCloudVaried = 15,
|
|
4488
|
+
/**
|
|
4489
|
+
* 0x10 - SpriteCloudVariedMultiColor: Different multicolor sprites at multiple positions
|
|
4490
|
+
*/
|
|
4491
|
+
SpriteCloudVariedMultiColor = 16,
|
|
4492
|
+
/**
|
|
4493
|
+
* 0x11 - Bitmask: Bitpacked presence/absence mask with uniform character and colors
|
|
4494
|
+
*/
|
|
4495
|
+
Bitmask = 17,
|
|
4496
|
+
/**
|
|
4497
|
+
* 0x13 - Clear: Fills entire layer with single character and colors
|
|
4498
|
+
*/
|
|
4499
|
+
Clear = 19,
|
|
4500
|
+
/**
|
|
4501
|
+
* 0x14 - FillChar: Fills layer with repeating character pattern
|
|
4502
|
+
*/
|
|
4503
|
+
FillChar = 20,
|
|
4504
|
+
/**
|
|
4505
|
+
* 0x15 - FillSprite: Fills layer with repeating unicolor sprite
|
|
4506
|
+
*/
|
|
4507
|
+
FillSprite = 21,
|
|
4508
|
+
/**
|
|
4509
|
+
* 0x16 - FillSpriteMultiColor: Fills layer with repeating multicolor sprite
|
|
4510
|
+
*/
|
|
4511
|
+
FillSpriteMultiColor = 22,
|
|
4512
|
+
/**
|
|
4513
|
+
* 0x20 - TriggerSound: Triggers positional sound effect
|
|
4514
|
+
*/
|
|
4515
|
+
TriggerSound = 32,
|
|
4516
|
+
/**
|
|
4517
|
+
* 0x21 - TriggerGlobalSound: Triggers global (non-positional) sound
|
|
4518
|
+
*/
|
|
4519
|
+
TriggerGlobalSound = 33
|
|
4520
|
+
}
|
|
4521
|
+
/**
|
|
4522
|
+
* Type guard to check if a number is a valid OrderType
|
|
4523
|
+
*/
|
|
4524
|
+
declare function isValidOrderType(type: number): type is OrderType;
|
|
4525
|
+
/**
|
|
4526
|
+
* Get human-readable name for an OrderType
|
|
4527
|
+
*/
|
|
4528
|
+
declare function getOrderTypeName(type: OrderType | number): string;
|
|
4529
|
+
|
|
4530
|
+
/**
|
|
4531
|
+
* UpdateFlags to optimize layer transmission
|
|
4532
|
+
*
|
|
4533
|
+
* Bitpacked flags (8 bits) to indicate layer state and changes.
|
|
4534
|
+
* Allows optimizing rendering and network transmission.
|
|
4535
|
+
*
|
|
4536
|
+
* @see UTSP Protocol section 5.4 - Layer UpdateFlags
|
|
4537
|
+
*/
|
|
4538
|
+
declare enum UpdateFlags {
|
|
4539
|
+
/**
|
|
4540
|
+
* Bit 0: Layer Enabled
|
|
4541
|
+
*
|
|
4542
|
+
* Indicates if the layer is enabled and should be rendered.
|
|
4543
|
+
* - 1 = Layer enabled, will be rendered by DisplayRasterizer
|
|
4544
|
+
* - 0 = Layer disabled, ignored during rendering
|
|
4545
|
+
*
|
|
4546
|
+
* Use cases:
|
|
4547
|
+
* - Show/hide layers without deleting them
|
|
4548
|
+
* - Toggle UI elements (inventory, menu, etc.)
|
|
4549
|
+
* - Temporarily disable a layer for optimization
|
|
4550
|
+
*
|
|
4551
|
+
* @example
|
|
4552
|
+
* layer.setEnabled(true);
|
|
4553
|
+
* // → UpdateFlags |= LayerEnabled (0x01)
|
|
4554
|
+
*/
|
|
4555
|
+
LayerEnabled = 1,
|
|
4556
|
+
/**
|
|
4557
|
+
* Bit 1: SET Mode (vs ADD mode)
|
|
4558
|
+
*
|
|
4559
|
+
* Indicates the order rasterization mode:
|
|
4560
|
+
* - 1 = SET mode → LayerRasterizer clears buffer before rasterizing
|
|
4561
|
+
* - 0 = ADD mode → LayerRasterizer adds to existing buffer
|
|
4562
|
+
*
|
|
4563
|
+
* Use cases:
|
|
4564
|
+
* - SET mode: layer.setOrders() - completely replaces content
|
|
4565
|
+
* - ADD mode: layer.addOrders() - adds to existing content
|
|
4566
|
+
*
|
|
4567
|
+
* IMPORTANT: Corresponds to RasterizeMode.SET vs RasterizeMode.ADD
|
|
4568
|
+
*
|
|
4569
|
+
* @example
|
|
4570
|
+
* layer.setOrders([...newOrders]); // SET mode
|
|
4571
|
+
* // → UpdateFlags |= SetMode (0x02)
|
|
4572
|
+
*
|
|
4573
|
+
* layer.addOrders([...moreOrders]); // ADD mode
|
|
4574
|
+
* // → UpdateFlags &= ~SetMode (bit 1 to 0)
|
|
4575
|
+
*/
|
|
4576
|
+
SetMode = 2,
|
|
4577
|
+
/**
|
|
4578
|
+
* Bit 2: Update position (originX/Y)
|
|
4579
|
+
*
|
|
4580
|
+
* Indicates that the layer's origin has changed.
|
|
4581
|
+
* If this bit is not set, the decoder keeps the existing position.
|
|
4582
|
+
*
|
|
4583
|
+
* Use cases:
|
|
4584
|
+
* - Parallax scrolling
|
|
4585
|
+
* - Camera following player
|
|
4586
|
+
* - Move a layer without modifying its content
|
|
4587
|
+
*
|
|
4588
|
+
* @example
|
|
4589
|
+
* layer.setOrigin(new Vector2(100, 50));
|
|
4590
|
+
* // → UpdateFlags |= UpdatePosition (0x04)
|
|
4591
|
+
*/
|
|
4592
|
+
UpdatePosition = 4,
|
|
4593
|
+
/**
|
|
4594
|
+
* Bit 3: Update z-index order
|
|
4595
|
+
*
|
|
4596
|
+
* Indicates that the layer's z-index has changed.
|
|
4597
|
+
* If this bit is not set, the decoder keeps the existing z-index.
|
|
4598
|
+
*
|
|
4599
|
+
* Use cases:
|
|
4600
|
+
* - Dynamically reorder layers
|
|
4601
|
+
* - Change rendering priority
|
|
4602
|
+
* - Bring a layer to the foreground
|
|
4603
|
+
*
|
|
4604
|
+
* @example
|
|
4605
|
+
* layer.setZOrder(10);
|
|
4606
|
+
* // → UpdateFlags |= UpdateZOrder (0x08)
|
|
4607
|
+
*/
|
|
4608
|
+
UpdateZOrder = 8,
|
|
4609
|
+
/**
|
|
4610
|
+
* No changes, layer disabled
|
|
4611
|
+
* Layer ignored during rendering
|
|
4612
|
+
*/
|
|
4613
|
+
Disabled = 0,
|
|
4614
|
+
/**
|
|
4615
|
+
* Layer enabled, ADD mode, no changes
|
|
4616
|
+
* Used to maintain an active layer without modifications
|
|
4617
|
+
*/
|
|
4618
|
+
EnabledAddMode = 1,// 0x01
|
|
4619
|
+
/**
|
|
4620
|
+
* Layer enabled, SET mode, no changes
|
|
4621
|
+
* Active layer in SET mode (overwrites buffer)
|
|
4622
|
+
*/
|
|
4623
|
+
EnabledSetMode = 3,// 0x03
|
|
4624
|
+
/**
|
|
4625
|
+
* Layer enabled, ADD mode, position changed (parallax scrolling)
|
|
4626
|
+
* Typical use case: scrolling background
|
|
4627
|
+
*/
|
|
4628
|
+
EnabledAddMoveOnly = 5,// 0x05
|
|
4629
|
+
/**
|
|
4630
|
+
* Layer enabled, SET mode, position changed
|
|
4631
|
+
*/
|
|
4632
|
+
EnabledSetMoveOnly = 7,// 0x07
|
|
4633
|
+
/**
|
|
4634
|
+
* Layer enabled, ADD mode, z-index changed
|
|
4635
|
+
*/
|
|
4636
|
+
EnabledAddReorderOnly = 9,// 0x09
|
|
4637
|
+
/**
|
|
4638
|
+
* Layer enabled, SET mode, z-index changed
|
|
4639
|
+
*/
|
|
4640
|
+
EnabledSetReorderOnly = 11,// 0x0B
|
|
4641
|
+
/**
|
|
4642
|
+
* Full update: Layer enabled, SET mode, position + z-index changed
|
|
4643
|
+
* Used for a complete change
|
|
4644
|
+
*/
|
|
4645
|
+
FullUpdate = 15
|
|
4646
|
+
}
|
|
4647
|
+
/**
|
|
4648
|
+
* Helper functions to manipulate UpdateFlags
|
|
4649
|
+
*/
|
|
4650
|
+
declare namespace UpdateFlagsHelper {
|
|
4651
|
+
/**
|
|
4652
|
+
* Checks if a specific flag is enabled
|
|
4653
|
+
*/
|
|
4654
|
+
function hasFlag(flags: number, flag: UpdateFlags): boolean;
|
|
4655
|
+
/**
|
|
4656
|
+
* Adds a flag
|
|
4657
|
+
*/
|
|
4658
|
+
function addFlag(flags: number, flag: UpdateFlags): number;
|
|
4659
|
+
/**
|
|
4660
|
+
* Removes a flag
|
|
4661
|
+
*/
|
|
4662
|
+
function removeFlag(flags: number, flag: UpdateFlags): number;
|
|
4663
|
+
/**
|
|
4664
|
+
* Combines multiple flags
|
|
4665
|
+
*/
|
|
4666
|
+
function combine(...flags: UpdateFlags[]): number;
|
|
4667
|
+
/**
|
|
4668
|
+
* Checks if flags are valid (bits 4-7 must be 0)
|
|
4669
|
+
*/
|
|
4670
|
+
function isValid(flags: number): boolean;
|
|
4671
|
+
/**
|
|
4672
|
+
* Checks if the layer is enabled (bit 0)
|
|
4673
|
+
*/
|
|
4674
|
+
function isEnabled(flags: number): boolean;
|
|
4675
|
+
/**
|
|
4676
|
+
* Checks if the mode is SET (bit 1)
|
|
4677
|
+
*/
|
|
4678
|
+
function isSetMode(flags: number): boolean;
|
|
4679
|
+
/**
|
|
4680
|
+
* Checks if the position has changed (bit 2)
|
|
4681
|
+
*/
|
|
4682
|
+
function hasPositionChanged(flags: number): boolean;
|
|
4683
|
+
/**
|
|
4684
|
+
* Checks if the z-index has changed (bit 3)
|
|
4685
|
+
*/
|
|
4686
|
+
function hasZOrderChanged(flags: number): boolean;
|
|
4687
|
+
/**
|
|
4688
|
+
* Returns a human-readable description of active flags
|
|
4689
|
+
*/
|
|
4690
|
+
function describe(flags: number): string;
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
/**
|
|
4694
|
+
* Decoder for UTSP Update Packets
|
|
4695
|
+
* Decodes complete update packets following the UTSP protocol specification (new architecture)
|
|
4696
|
+
*/
|
|
4697
|
+
declare class UpdatePacketDecoder {
|
|
4698
|
+
private displayDecoder;
|
|
4699
|
+
private layerDecoder;
|
|
4700
|
+
constructor();
|
|
4701
|
+
/**
|
|
4702
|
+
* Decodes an UpdatePacket from binary buffer
|
|
4703
|
+
*
|
|
4704
|
+
* Structure (NEW PROTOCOL):
|
|
4705
|
+
* - Tick: 8 bytes (big-endian, 64-bit unsigned integer)
|
|
4706
|
+
* - DisplayCount: 1 byte (8-bit unsigned integer, max 255 displays)
|
|
4707
|
+
* - Displays: variable (DisplayId + OriginX + OriginY + SizeX + SizeY = 7 bytes each)
|
|
4708
|
+
* - LayerCount: 2 bytes (big-endian, 16-bit unsigned integer)
|
|
4709
|
+
* - Layers: variable (encoded layers)
|
|
4710
|
+
*
|
|
4711
|
+
* Minimum packet size: 11 bytes (Tick + DisplayCount + LayerCount)
|
|
4712
|
+
*/
|
|
4713
|
+
decode(data: Uint8Array, offset?: number): UpdatePacket;
|
|
4714
|
+
/**
|
|
4715
|
+
* Checks if a buffer contains a valid update packet header
|
|
4716
|
+
* Useful for validation before decoding
|
|
4717
|
+
*/
|
|
4718
|
+
isValid(data: Uint8Array, offset?: number): boolean;
|
|
4719
|
+
/**
|
|
4720
|
+
* Decodes only the tick and counts without decoding the displays/layers
|
|
4721
|
+
* Useful for quick inspection of packet metadata
|
|
4722
|
+
*/
|
|
4723
|
+
decodeHeader(data: Uint8Array, offset?: number): {
|
|
4724
|
+
tick: number;
|
|
4725
|
+
displayCount: number;
|
|
4726
|
+
layerCount: number;
|
|
4727
|
+
};
|
|
4728
|
+
private checkSize;
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
export { ASCII_8X8_FONT, BITMASK_ORDER_MIN_SIZE, BitmapFont, BitmapFontRegistry, CHAR_ORDER_SIZE, CIRCLE_SHAPE_SIZE, CLEAR_ORDER_SIZE, COLORMAP_ORDER_MIN_SIZE, COLOR_SKIP, CellBuffer, CharCodeBuffer, Core, CoreStats, DISPLAY_HEADER_SIZE, DOTCLOUD_MULTICOLOR_ORDER_MIN_SIZE, DOTCLOUD_ORDER_MIN_SIZE, Display, ELLIPSE_SHAPE_SIZE, FILLCHAR_ORDER_MIN_SIZE, FILLSPRITE_MULTICOLOR_ORDER_SIZE, FILLSPRITE_ORDER_SIZE, FULLFRAME_MULTICOLOR_ORDER_MIN_SIZE, FULLFRAME_ORDER_MIN_SIZE, FontType, InputBindingRegistry, LAYER_CELL_COUNT, LAYER_HEADER_SIZE, LAYER_SIZE, LINE_SHAPE_SIZE, Layer, LoadType, OrderBuilder, OrderType, RECTANGLE_SHAPE_SIZE, SHAPE_ORDER_MIN_SIZE, SPRITECLOUD_MULTICOLOR_ORDER_MIN_SIZE, SPRITECLOUD_ORDER_MIN_SIZE, SPRITECLOUD_VARIED_MULTICOLOR_ORDER_MIN_SIZE, SPRITECLOUD_VARIED_ORDER_MIN_SIZE, SPRITE_MULTICOLOR_ORDER_SIZE, SPRITE_ORDER_SIZE, SUBFRAME_MULTICOLOR_ORDER_MIN_SIZE, SUBFRAME_ORDER_MIN_SIZE, ShapeType, SpriteRegistry, TEXT_MULTILINE_ORDER_MIN_SIZE, TEXT_ORDER_MIN_SIZE, TRIANGLE_SHAPE_SIZE, TRIGGERGLOBALSOUND_ORDER_SIZE, TRIGGERSOUND_ORDER_SIZE, UPDATE_PACKET_HEADER_SIZE, UpdateFlags, UpdateFlagsHelper, UpdatePacketDecoder, User, UserStats, WebFont, WebFontRegistry, createASCII8x8FontLoad, createEmptyCompressedInputPacket, decodeCompressedInput, decodeInt8ToAxis, encodeAxisToInt8, encodeCompressedInput, getASCII8x8FontConfig, getAllCharCodes, getButtonByteCount, getCharBitmap, getCompressedPacketSize, getOrderTypeName, hasChar, isValidOrderType };
|
|
4732
|
+
export type { AnyLoad, BitmapFontConfig, BitmapFontLoad, Cell, CircleShape, Color, ColorPaletteLoad, CompressedInputPacket, CoreMode, CoreOptions, EllipseShape, LineShape, MulticolorCell, MulticolorSprite, MulticolorSpriteLoad, NetworkDisplay, NetworkLayer, RectangleShape, ShapeData, SoundLoad, SpriteLoad, TickStats, TriangleShape, UnicolorSprite, UpdatePacket, UserTickStats, WebFontConfig, WebFontLoad };
|