xiv-strat-board 0.1.3 → 0.2.0
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/README.md +5 -5
- package/dist/index.cjs +87 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +87 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ Decodes a share code to a strategy board.
|
|
|
75
75
|
|
|
76
76
|
```typescript
|
|
77
77
|
interface StrategyBoard {
|
|
78
|
-
name?: string; // Max
|
|
78
|
+
name?: string; // Max 20 characters
|
|
79
79
|
boardBackground?: BackgroundType;
|
|
80
80
|
objects: StrategyObject[];
|
|
81
81
|
}
|
|
@@ -89,7 +89,7 @@ interface StrategyObject {
|
|
|
89
89
|
typeId?: number; // Optional numeric ID (overrides type)
|
|
90
90
|
x: number; // 0-512, center at 256
|
|
91
91
|
y: number; // 0-384, center at 192
|
|
92
|
-
size?: number; //
|
|
92
|
+
size?: number; // 10-200, default 100 (text always 100)
|
|
93
93
|
background?: BackgroundType;
|
|
94
94
|
|
|
95
95
|
// Color (only for line_aoe, line, text)
|
|
@@ -97,8 +97,8 @@ interface StrategyObject {
|
|
|
97
97
|
transparency?: number; // 0-255
|
|
98
98
|
|
|
99
99
|
// AoE properties
|
|
100
|
-
arcAngle?: number; //
|
|
101
|
-
donutRadius?: number; // 0-255
|
|
100
|
+
arcAngle?: number; // 0-360, intervals of 10
|
|
101
|
+
donutRadius?: number; // 0-255 (0 = full circle/no hole)
|
|
102
102
|
|
|
103
103
|
// Line AoE properties
|
|
104
104
|
width?: number; // Width for line_aoe
|
|
@@ -117,7 +117,7 @@ interface StrategyObject {
|
|
|
117
117
|
verticalCount?: number; // Vertical count for linear_knockback
|
|
118
118
|
|
|
119
119
|
// Text objects
|
|
120
|
-
text?: string; // Text content
|
|
120
|
+
text?: string; // Text content (max 30 chars)
|
|
121
121
|
|
|
122
122
|
// Flip states
|
|
123
123
|
horizontalFlip?: boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -371,15 +371,6 @@ var BOARD_BACKGROUND_IDS = {
|
|
|
371
371
|
grey_circle: 6,
|
|
372
372
|
grey_square: 7
|
|
373
373
|
};
|
|
374
|
-
var OBJECT_BACKGROUND_IDS = {
|
|
375
|
-
none: 0,
|
|
376
|
-
checkered: 1,
|
|
377
|
-
checkered_circle: 2,
|
|
378
|
-
checkered_square: 3,
|
|
379
|
-
grey: 4,
|
|
380
|
-
grey_circle: 5,
|
|
381
|
-
grey_square: 6
|
|
382
|
-
};
|
|
383
374
|
|
|
384
375
|
// src/validation.ts
|
|
385
376
|
var BOUNDS = {
|
|
@@ -392,9 +383,9 @@ var BOUNDS = {
|
|
|
392
383
|
/** Maximum Y coordinate */
|
|
393
384
|
maxY: 484,
|
|
394
385
|
/** Minimum size percentage */
|
|
395
|
-
minSize:
|
|
386
|
+
minSize: 10,
|
|
396
387
|
/** Maximum size percentage */
|
|
397
|
-
maxSize:
|
|
388
|
+
maxSize: 200,
|
|
398
389
|
/** Minimum arc angle */
|
|
399
390
|
minArc: 0,
|
|
400
391
|
/** Maximum arc angle */
|
|
@@ -405,8 +396,10 @@ var BOUNDS = {
|
|
|
405
396
|
maxDonut: 255,
|
|
406
397
|
/** Maximum number of objects per board */
|
|
407
398
|
maxObjects: 50,
|
|
399
|
+
/** Maximum number of text objects per board */
|
|
400
|
+
maxTextObjects: 8,
|
|
408
401
|
/** Maximum name length (bytes) */
|
|
409
|
-
maxNameLength:
|
|
402
|
+
maxNameLength: 20
|
|
410
403
|
};
|
|
411
404
|
var VALID_CIPHER_CHARS = new Set(
|
|
412
405
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_".split("")
|
|
@@ -481,19 +474,6 @@ function parseHexColor(color) {
|
|
|
481
474
|
b: parseInt(hex.slice(4, 6), 16)
|
|
482
475
|
};
|
|
483
476
|
}
|
|
484
|
-
function validateBackground(value) {
|
|
485
|
-
if (typeof value === "number") {
|
|
486
|
-
if (value >= 0 && value <= 6) {
|
|
487
|
-
return value;
|
|
488
|
-
}
|
|
489
|
-
return 0;
|
|
490
|
-
}
|
|
491
|
-
if (typeof value === "string") {
|
|
492
|
-
const id = OBJECT_BACKGROUND_IDS[value.toLowerCase()];
|
|
493
|
-
return id ?? 0;
|
|
494
|
-
}
|
|
495
|
-
return 0;
|
|
496
|
-
}
|
|
497
477
|
function validateBoardBackground(value) {
|
|
498
478
|
if (typeof value === "string") {
|
|
499
479
|
const id = BOARD_BACKGROUND_IDS[value.toLowerCase()];
|
|
@@ -544,16 +524,26 @@ function sanitizeObject(obj, index) {
|
|
|
544
524
|
typeId,
|
|
545
525
|
x: sanitizeCoordinate(obj.x, true),
|
|
546
526
|
y: sanitizeCoordinate(obj.y, false),
|
|
547
|
-
size: sanitizeSize(obj.size),
|
|
548
|
-
|
|
527
|
+
size: typeId === 100 ? 100 : sanitizeSize(obj.size),
|
|
528
|
+
angle: Math.round(obj.angle ?? 0),
|
|
549
529
|
colorR: sanitizeColorComponent(colorR),
|
|
550
530
|
colorG: sanitizeColorComponent(colorG),
|
|
551
531
|
colorB: sanitizeColorComponent(colorB),
|
|
552
532
|
transparency: sanitizeColorComponent(obj.transparency ?? 0),
|
|
553
|
-
arcAngle: clamp(Math.round(obj.arcAngle ?? 0), BOUNDS.minArc, BOUNDS.maxArc),
|
|
533
|
+
arcAngle: clamp(Math.round((obj.arcAngle ?? 0) / 10) * 10, BOUNDS.minArc, BOUNDS.maxArc),
|
|
554
534
|
donutRadius: clamp(Math.round(obj.donutRadius ?? 0), BOUNDS.minDonut, BOUNDS.maxDonut),
|
|
535
|
+
width: Math.round(obj.width ?? 0),
|
|
536
|
+
height: Math.round(obj.height ?? 0),
|
|
537
|
+
endX: sanitizeCoordinate(obj.endX ?? 0, true),
|
|
538
|
+
endY: sanitizeCoordinate(obj.endY ?? 0, false),
|
|
539
|
+
displayCount: Math.round(obj.displayCount ?? 0),
|
|
540
|
+
horizontalCount: Math.round(obj.horizontalCount ?? 0),
|
|
541
|
+
verticalCount: Math.round(obj.verticalCount ?? 0),
|
|
542
|
+
text: typeof obj.text === "string" ? obj.text.slice(0, 30) : "",
|
|
555
543
|
hidden: Boolean(obj.hidden),
|
|
556
|
-
locked: Boolean(obj.locked)
|
|
544
|
+
locked: Boolean(obj.locked),
|
|
545
|
+
horizontalFlip: Boolean(obj.horizontalFlip),
|
|
546
|
+
verticalFlip: Boolean(obj.verticalFlip)
|
|
557
547
|
};
|
|
558
548
|
}
|
|
559
549
|
function sanitizeBoard(board) {
|
|
@@ -566,6 +556,10 @@ function sanitizeBoard(board) {
|
|
|
566
556
|
if (board.objects.length > BOUNDS.maxObjects) {
|
|
567
557
|
throw new Error(`Board has too many objects (max ${BOUNDS.maxObjects})`);
|
|
568
558
|
}
|
|
559
|
+
const textCount = board.objects.filter((obj) => obj.type === "text" || obj.typeId === 100).length;
|
|
560
|
+
if (textCount > BOUNDS.maxTextObjects) {
|
|
561
|
+
throw new Error(`Board has too many text objects (max ${BOUNDS.maxTextObjects})`);
|
|
562
|
+
}
|
|
569
563
|
return {
|
|
570
564
|
name: sanitizeName(board.name),
|
|
571
565
|
boardBackground: validateBoardBackground(board.boardBackground),
|
|
@@ -789,7 +783,7 @@ function parseBinary(data) {
|
|
|
789
783
|
x: positions[i]?.x ?? 0,
|
|
790
784
|
y: positions[i]?.y ?? 0
|
|
791
785
|
};
|
|
792
|
-
obj.size = sizes[i] && sizes[i] > 0 ? sizes[i] : 100;
|
|
786
|
+
obj.size = iconId === 100 ? 100 : sizes[i] && sizes[i] > 0 ? sizes[i] : 100;
|
|
793
787
|
if (iconId !== 100 && backgrounds[i] !== void 0 && backgrounds[i] !== 0) {
|
|
794
788
|
obj.angle = backgrounds[i];
|
|
795
789
|
}
|
|
@@ -837,10 +831,10 @@ function parseBinary(data) {
|
|
|
837
831
|
obj.verticalCount = tag11[i];
|
|
838
832
|
}
|
|
839
833
|
} else if (iconId === 17) {
|
|
840
|
-
if (tag10[i] && tag10[i] > 0) {
|
|
834
|
+
if (tag10[i] !== void 0 && tag10[i] > 0) {
|
|
841
835
|
obj.arcAngle = tag10[i];
|
|
842
836
|
}
|
|
843
|
-
if (tag11[i]
|
|
837
|
+
if (tag11[i] !== void 0) {
|
|
844
838
|
obj.donutRadius = tag11[i];
|
|
845
839
|
}
|
|
846
840
|
} else {
|
|
@@ -879,9 +873,20 @@ function parseBinary(data) {
|
|
|
879
873
|
function buildBinary(data) {
|
|
880
874
|
const { name, boardBackground, objects } = data;
|
|
881
875
|
const n = objects.length;
|
|
876
|
+
const nameBytes = new TextEncoder().encode(name.slice(0, 20));
|
|
877
|
+
const namePaddedLen = Math.max(8, nameBytes.length + 1 + 3 & -4);
|
|
878
|
+
const headerSize = 28 + namePaddedLen;
|
|
882
879
|
const tag4Size = n <= 1 ? 8 : 6 + n * 2;
|
|
883
880
|
const tag7Size = 6 + n + (n % 2 === 1 ? 1 : 0);
|
|
884
|
-
|
|
881
|
+
let textContentSize = 0;
|
|
882
|
+
for (const obj of objects) {
|
|
883
|
+
if (obj.typeId === 100 && obj.text) {
|
|
884
|
+
const textLen = new TextEncoder().encode(obj.text).length;
|
|
885
|
+
const paddedLen = Math.max(8, textLen + 1 + 3 & -4);
|
|
886
|
+
textContentSize += 4 + paddedLen;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
const bufferSize = n === 0 ? headerSize + 8 : headerSize + n * 4 + textContentSize + tag4Size + (6 + n * 4) + (6 + n * 2) + tag7Size + (6 + n * 4) + (6 + n * 2) + (6 + n * 2) + (6 + n * 2) + 8;
|
|
885
890
|
const buffer = new ArrayBuffer(bufferSize);
|
|
886
891
|
const view = new DataView(buffer);
|
|
887
892
|
let pos = 0;
|
|
@@ -907,33 +912,45 @@ function buildBinary(data) {
|
|
|
907
912
|
writeUint32(0);
|
|
908
913
|
writeUint16(0);
|
|
909
914
|
writeUint16(1);
|
|
910
|
-
writeUint16(
|
|
911
|
-
|
|
912
|
-
for (let i = 0; i < 8; i++) {
|
|
915
|
+
writeUint16(namePaddedLen);
|
|
916
|
+
for (let i = 0; i < namePaddedLen; i++) {
|
|
913
917
|
writeUint8(nameBytes[i] ?? 0);
|
|
914
918
|
}
|
|
915
919
|
for (const obj of objects) {
|
|
916
920
|
writeUint16(2);
|
|
917
921
|
writeUint16(obj.typeId);
|
|
922
|
+
if (obj.typeId === 100 && obj.text) {
|
|
923
|
+
const textBytes = new TextEncoder().encode(obj.text);
|
|
924
|
+
const paddedLen = Math.max(8, textBytes.length + 1 + 3 & -4);
|
|
925
|
+
writeUint16(3);
|
|
926
|
+
writeUint16(paddedLen);
|
|
927
|
+
for (let i = 0; i < paddedLen; i++) {
|
|
928
|
+
writeUint8(textBytes[i] ?? 0);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
918
931
|
}
|
|
919
932
|
if (n === 0) ; else if (n === 1) {
|
|
920
933
|
writeUint16(4);
|
|
921
934
|
writeUint16(1);
|
|
922
935
|
const obj = objects[0];
|
|
923
936
|
let flagsVal = 1;
|
|
924
|
-
if (obj.hidden)
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
937
|
+
if (obj.hidden) flagsVal &= -2;
|
|
938
|
+
if (obj.horizontalFlip) flagsVal |= 2;
|
|
939
|
+
if (obj.verticalFlip) flagsVal |= 4;
|
|
940
|
+
if (obj.locked) flagsVal |= 8;
|
|
929
941
|
writeUint16(1);
|
|
930
942
|
writeUint16(flagsVal);
|
|
931
943
|
} else {
|
|
932
944
|
writeUint16(4);
|
|
933
945
|
writeUint16(1);
|
|
934
946
|
writeUint16(n);
|
|
935
|
-
for (
|
|
936
|
-
|
|
947
|
+
for (const obj of objects) {
|
|
948
|
+
let flagsVal = 1;
|
|
949
|
+
if (obj.hidden) flagsVal &= -2;
|
|
950
|
+
if (obj.horizontalFlip) flagsVal |= 2;
|
|
951
|
+
if (obj.verticalFlip) flagsVal |= 4;
|
|
952
|
+
if (obj.locked) flagsVal |= 8;
|
|
953
|
+
writeUint16(flagsVal);
|
|
937
954
|
}
|
|
938
955
|
}
|
|
939
956
|
if (n > 0) {
|
|
@@ -948,7 +965,7 @@ function buildBinary(data) {
|
|
|
948
965
|
writeUint16(1);
|
|
949
966
|
writeUint16(n);
|
|
950
967
|
for (const obj of objects) {
|
|
951
|
-
|
|
968
|
+
writeInt16(obj.angle);
|
|
952
969
|
}
|
|
953
970
|
writeUint16(7);
|
|
954
971
|
writeUint16(0);
|
|
@@ -972,19 +989,41 @@ function buildBinary(data) {
|
|
|
972
989
|
writeUint16(1);
|
|
973
990
|
writeUint16(n);
|
|
974
991
|
for (const obj of objects) {
|
|
975
|
-
|
|
992
|
+
if (obj.typeId === 11) {
|
|
993
|
+
writeUint16(obj.width);
|
|
994
|
+
} else if (obj.typeId === 12) {
|
|
995
|
+
writeUint16(Math.round(obj.endX * 10));
|
|
996
|
+
} else if (obj.typeId === 110) {
|
|
997
|
+
writeUint16(obj.horizontalCount);
|
|
998
|
+
} else {
|
|
999
|
+
writeUint16(obj.arcAngle);
|
|
1000
|
+
}
|
|
976
1001
|
}
|
|
977
1002
|
writeUint16(11);
|
|
978
1003
|
writeUint16(1);
|
|
979
1004
|
writeUint16(n);
|
|
980
1005
|
for (const obj of objects) {
|
|
981
|
-
|
|
1006
|
+
if (obj.typeId === 11) {
|
|
1007
|
+
writeUint16(obj.height);
|
|
1008
|
+
} else if (obj.typeId === 12) {
|
|
1009
|
+
writeUint16(Math.round(obj.endY * 10));
|
|
1010
|
+
} else if (obj.typeId === 15) {
|
|
1011
|
+
writeUint16(obj.displayCount);
|
|
1012
|
+
} else if (obj.typeId === 110) {
|
|
1013
|
+
writeUint16(obj.verticalCount);
|
|
1014
|
+
} else {
|
|
1015
|
+
writeUint16(obj.donutRadius);
|
|
1016
|
+
}
|
|
982
1017
|
}
|
|
983
1018
|
writeUint16(12);
|
|
984
1019
|
writeUint16(1);
|
|
985
1020
|
writeUint16(n);
|
|
986
|
-
for (
|
|
987
|
-
|
|
1021
|
+
for (const obj of objects) {
|
|
1022
|
+
if (obj.typeId === 12) {
|
|
1023
|
+
writeUint16(obj.height);
|
|
1024
|
+
} else {
|
|
1025
|
+
writeUint16(0);
|
|
1026
|
+
}
|
|
988
1027
|
}
|
|
989
1028
|
}
|
|
990
1029
|
writeUint16(3);
|