adofai-lib 1.0.1 → 1.0.3

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.
@@ -0,0 +1,17 @@
1
+ import { Action, Decoration } from './types';
2
+ export declare class Level {
3
+ private filename;
4
+ private encoding;
5
+ private tiles;
6
+ private nonFloorDecos;
7
+ private settings;
8
+ constructor(filename?: string, encoding?: BufferEncoding);
9
+ private getFileString;
10
+ private getFileDict;
11
+ getAngles(): number[];
12
+ setAngles(angles: number[]): void;
13
+ getAnglesRelative(ignoreTwirls?: boolean, padMidspins?: boolean): number[];
14
+ getActions(condition?: (action: Action) => boolean): Action[];
15
+ getDecorations(condition?: (decoration: Decoration) => boolean): Decoration[];
16
+ writeToFile(filename?: string): void;
17
+ }
package/dist/Level.js ADDED
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Level = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const types_1 = require("./types");
39
+ class Level {
40
+ constructor(filename = '', encoding = 'utf-8') {
41
+ this.filename = filename;
42
+ this.encoding = encoding;
43
+ this.tiles = [];
44
+ this.nonFloorDecos = [];
45
+ this.settings = {};
46
+ const leveldict = this.getFileDict();
47
+ if (!leveldict.actions || !leveldict.settings || (!leveldict.angleData && !leveldict.pathData)) {
48
+ throw new types_1.InvalidLevelException(`The provided .adofai file is invalid. (missing: ${!leveldict.actions ? 'actions' : ''} ${!leveldict.settings ? 'settings' : ''} ${!leveldict.angleData && !leveldict.pathData ? 'angleData or pathData' : ''})`);
49
+ }
50
+ let angleData;
51
+ if ('angleData' in leveldict) {
52
+ angleData = leveldict.angleData;
53
+ }
54
+ else {
55
+ const pathchars = {
56
+ 'R': 0, 'p': 15, 'J': 30, 'E': 45, 'T': 60, 'o': 75, 'U': 90,
57
+ 'q': 105, 'G': 120, 'Q': 135, 'H': 150, 'W': 165, 'L': 180,
58
+ 'x': 195, 'N': 210, 'Z': 225, 'F': 240, 'V': 255, 'D': 270,
59
+ 'Y': 285, 'B': 300, 'C': 315, 'M': 330, 'A': 345, '!': 999
60
+ };
61
+ angleData = Array.from(leveldict.pathData).map(char => pathchars[char]);
62
+ }
63
+ angleData.push(angleData[angleData.length - 1] !== 999 ? angleData[angleData.length - 1] : (angleData[angleData.length - 2] + 180) % 360);
64
+ const actions = leveldict.actions;
65
+ const decorations = leveldict.decorations || [];
66
+ this.nonFloorDecos = decorations.filter((j) => !('floor' in j)).map((j) => ({ ...j }));
67
+ this.settings = filename !== '' ? { ...leveldict.settings } : {};
68
+ // Initialize tiles
69
+ this.tiles = angleData.map(angle => ({
70
+ angle,
71
+ actions: [],
72
+ decorations: []
73
+ }));
74
+ // Add actions
75
+ actions.forEach((action) => {
76
+ if (action.floor !== undefined && action.floor < this.tiles.length) {
77
+ this.tiles[action.floor].actions.push({ ...action });
78
+ }
79
+ });
80
+ // Add decorations
81
+ decorations.forEach((deco) => {
82
+ if ('floor' in deco) {
83
+ if (deco.floor >= this.tiles.length) {
84
+ this.tiles[this.tiles.length - 1].decorations.push({ ...deco });
85
+ }
86
+ else {
87
+ this.tiles[deco.floor].decorations.push({ ...deco });
88
+ }
89
+ }
90
+ });
91
+ }
92
+ getFileString() {
93
+ if (!this.filename)
94
+ return '';
95
+ return fs.readFileSync(this.filename, { encoding: this.encoding });
96
+ }
97
+ getFileDict() {
98
+ if (!this.filename) {
99
+ return {
100
+ angleData: [0],
101
+ settings: {},
102
+ actions: [],
103
+ decorations: []
104
+ };
105
+ }
106
+ const content = this.getFileString();
107
+ return JSON.parse(content);
108
+ }
109
+ getAngles() {
110
+ return this.tiles.map(tile => tile.angle);
111
+ }
112
+ setAngles(angles) {
113
+ if (angles.length > this.tiles.length) {
114
+ this.tiles.push({
115
+ angle: angles[angles.length - 1],
116
+ actions: [],
117
+ decorations: []
118
+ });
119
+ }
120
+ this.tiles = this.tiles.slice(0, angles.length);
121
+ this.tiles.forEach((tile, i) => {
122
+ tile.angle = angles[i];
123
+ });
124
+ }
125
+ getAnglesRelative(ignoreTwirls = false, padMidspins = false) {
126
+ const absangles = this.getAngles().slice(0, -1);
127
+ if (!ignoreTwirls) {
128
+ const twirls = this.getActions(action => action.eventType === 'Twirl')
129
+ .map(event => event.floor);
130
+ for (const twirl of twirls.reverse()) {
131
+ absangles.splice(twirl, absangles.length - twirl, ...absangles.slice(twirl).map(angle => angle !== 999 ? (2 * absangles[twirl - 1] - angle) % 360 : 999));
132
+ }
133
+ }
134
+ const midspins = absangles.map((angle, idx) => angle === 999 ? idx : -1).filter(idx => idx !== -1);
135
+ for (const midspin of midspins.reverse()) {
136
+ absangles.splice(midspin + 1, absangles.length - (midspin + 1), ...absangles.slice(midspin + 1).map(angle => angle !== 999 ? (angle + 180) % 360 : 999));
137
+ }
138
+ if (!padMidspins) {
139
+ absangles.splice(0, absangles.length, ...absangles.filter(angle => angle !== 999));
140
+ }
141
+ return absangles.map((angle, idx) => {
142
+ if (angle === 999)
143
+ return 0;
144
+ if (idx === 0)
145
+ return ((0 - angle + 180 - 1) % 360) + 1;
146
+ if (absangles[idx - 1] === 999) {
147
+ return ((absangles[idx - 2] - angle + 180 - 1) % 360) + 1;
148
+ }
149
+ return ((absangles[idx - 1] - angle + 180 - 1) % 360) + 1;
150
+ });
151
+ }
152
+ getActions(condition = () => true) {
153
+ return this.tiles.flatMap(tile => tile.actions.filter(condition));
154
+ }
155
+ getDecorations(condition = () => true) {
156
+ return [
157
+ ...this.tiles.flatMap(tile => tile.decorations.filter(condition)),
158
+ ...this.nonFloorDecos.filter(condition)
159
+ ];
160
+ }
161
+ writeToFile(filename) {
162
+ const final = {
163
+ angleData: this.tiles.map(tile => tile.angle),
164
+ settings: { ...this.settings },
165
+ actions: this.tiles.flatMap(tile => tile.actions),
166
+ decorations: [
167
+ ...this.tiles.flatMap(tile => tile.decorations),
168
+ ...this.nonFloorDecos
169
+ ]
170
+ };
171
+ const outputFile = filename || this.filename;
172
+ fs.writeFileSync(outputFile, JSON.stringify(final, null, 4), { encoding: this.encoding });
173
+ }
174
+ }
175
+ exports.Level = Level;
@@ -0,0 +1,18 @@
1
+ import { Action, Decoration } from './types';
2
+ export declare class LevelDict {
3
+ private filename;
4
+ private encoding;
5
+ private tiles;
6
+ private nonFloorDecos;
7
+ private settings;
8
+ constructor(filename?: string, encoding?: BufferEncoding);
9
+ private getFileString;
10
+ private getFileDict;
11
+ getAngles(): number[];
12
+ setAngles(angles: number[]): void;
13
+ getAnglesRelative(ignoreTwirls?: boolean, padMidspins?: boolean): number[];
14
+ getActions(condition?: (action: Action) => boolean): Action[];
15
+ getDecorations(condition?: (decoration: Decoration) => boolean): Decoration[];
16
+ writeToFile(filename?: string): void;
17
+ }
18
+ //# sourceMappingURL=LevelDict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LevelDict.d.ts","sourceRoot":"","sources":["../src/LevelDict.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,UAAU,EAA6C,MAAM,SAAS,CAAC;AAGxF,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAW;gBAEf,QAAQ,GAAE,MAAW,EAAE,QAAQ,GAAE,cAAwB;IAwDrE,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,WAAW;IAcZ,SAAS,IAAI,MAAM,EAAE;IAIrB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAcjC,iBAAiB,CAAC,YAAY,GAAE,OAAe,EAAE,WAAW,GAAE,OAAe,GAAG,MAAM,EAAE;IAuCxF,UAAU,CAAC,SAAS,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAoB,GAAG,MAAM,EAAE;IAIzE,cAAc,CAAC,SAAS,GAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAoB,GAAG,UAAU,EAAE;IAKzF,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAW5C"}
@@ -0,0 +1,136 @@
1
+ import * as fs from 'fs';
2
+ import * as utils from './utils/levelUtils';
3
+ import { InvalidLevelDictException } from './types';
4
+ export class LevelDict {
5
+ constructor(filename = '', encoding = 'utf-8') {
6
+ this.filename = filename;
7
+ this.encoding = encoding;
8
+ this.tiles = [];
9
+ this.nonFloorDecos = [];
10
+ this.settings = {};
11
+ const leveldict = this.getFileDict(filename);
12
+ if (!leveldict.actions || !leveldict.settings || (!leveldict.angleData && !leveldict.pathData)) {
13
+ throw new InvalidLevelDictException(`The provided .adofai file is invalid. (missing: ${!leveldict.actions ? 'actions' : ''} ${!leveldict.settings ? 'settings' : ''} ${!leveldict.angleData && !leveldict.pathData ? 'angleData or pathData' : ''})`);
14
+ }
15
+ let angleData;
16
+ if ('angleData' in leveldict) {
17
+ angleData = leveldict.angleData;
18
+ }
19
+ else {
20
+ const pathchars = {
21
+ 'R': 0, 'p': 15, 'J': 30, 'E': 45, 'T': 60, 'o': 75, 'U': 90,
22
+ 'q': 105, 'G': 120, 'Q': 135, 'H': 150, 'W': 165, 'L': 180,
23
+ 'x': 195, 'N': 210, 'Z': 225, 'F': 240, 'V': 255, 'D': 270,
24
+ 'Y': 285, 'B': 300, 'C': 315, 'M': 330, 'A': 345, '!': 999
25
+ };
26
+ angleData = Array.from(leveldict.pathData).map(char => pathchars[char]);
27
+ }
28
+ const actions = leveldict.actions;
29
+ const decorations = leveldict.decorations || [];
30
+ this.nonFloorDecos = decorations.filter((j) => !('floor' in j)).map((j) => ({ ...j }));
31
+ this.settings = filename !== '' ? { ...leveldict.settings } : {};
32
+ // Initialize tiles
33
+ this.tiles = angleData.map(angle => ({
34
+ angle,
35
+ actions: [],
36
+ decorations: []
37
+ }));
38
+ console.log('mapping tiles', angleData, this.tiles);
39
+ // Add actions
40
+ actions.forEach((action) => {
41
+ if (action.floor !== undefined && action.floor < this.tiles.length) {
42
+ this.tiles[action.floor].actions.push({ ...action });
43
+ }
44
+ });
45
+ // Add decorations
46
+ decorations.forEach((deco) => {
47
+ if ('floor' in deco) {
48
+ if (deco.floor >= this.tiles.length) {
49
+ this.tiles[this.tiles.length - 1].decorations.push({ ...deco });
50
+ }
51
+ else {
52
+ this.tiles[deco.floor].decorations.push({ ...deco });
53
+ }
54
+ }
55
+ });
56
+ }
57
+ getFileString(filename) {
58
+ if (!filename)
59
+ return '';
60
+ return fs.readFileSync(filename, { encoding: this.encoding });
61
+ }
62
+ getFileDict(filename) {
63
+ if (!filename) {
64
+ return {
65
+ angleData: [0],
66
+ settings: {},
67
+ actions: [],
68
+ decorations: []
69
+ };
70
+ }
71
+ const content = this.getFileString(filename);
72
+ return utils.safeParseJSON(content);
73
+ }
74
+ getAngles() {
75
+ return this.tiles.map(tile => tile.angle);
76
+ }
77
+ setAngles(angles) {
78
+ while (angles.length > this.tiles.length) {
79
+ this.tiles.push({
80
+ angle: angles[this.tiles.length],
81
+ actions: [],
82
+ decorations: []
83
+ });
84
+ }
85
+ this.tiles = this.tiles.slice(0, angles.length);
86
+ this.tiles.forEach((tile, i) => {
87
+ tile.angle = angles[i];
88
+ });
89
+ }
90
+ getAnglesRelative(ignoreTwirls = false, padMidspins = false) {
91
+ const absangles = this.getAngles();
92
+ if (!ignoreTwirls) {
93
+ const twirls = this.getActions(action => action.eventType === 'Twirl')
94
+ .map(event => event.floor);
95
+ for (const twirl of twirls.reverse()) {
96
+ absangles.splice(twirl, absangles.length - twirl, ...absangles.slice(twirl).map(angle => angle !== 999 ? (2 * absangles[twirl - 1] - angle) % 360 : 999));
97
+ }
98
+ }
99
+ const midspins = absangles.map((angle, idx) => angle === 999 ? idx : -1).filter(idx => idx !== -1);
100
+ for (const midspin of midspins.reverse()) {
101
+ absangles.splice(midspin + 1, absangles.length - (midspin + 1), ...absangles.slice(midspin + 1).map(angle => angle !== 999 ? (angle + 180) % 360 : 999));
102
+ }
103
+ if (!padMidspins) {
104
+ absangles.splice(0, absangles.length, ...absangles.filter(angle => angle !== 999));
105
+ }
106
+ return absangles.map((angle, idx) => {
107
+ if (angle === 999)
108
+ return 0;
109
+ if (idx === 0)
110
+ return ((0 - angle + 180 - 1) % 360) + 1;
111
+ if (absangles[idx - 1] === 999) {
112
+ return ((absangles[idx - 2] - angle + 180 - 1) % 360) + 1;
113
+ }
114
+ return ((absangles[idx - 1] - angle + 180 - 1) % 360) + 1;
115
+ });
116
+ }
117
+ getActions(condition = () => true) {
118
+ return this.tiles.flatMap(tile => tile.actions.filter(condition));
119
+ }
120
+ getDecorations(condition = () => true) {
121
+ return this.tiles.flatMap(tile => tile.decorations.filter(condition))
122
+ .concat(this.nonFloorDecos.filter(condition));
123
+ }
124
+ writeToFile(filename) {
125
+ const final = {
126
+ angleData: this.getAngles(),
127
+ settings: { ...this.settings },
128
+ actions: this.getActions(),
129
+ decorations: this.getDecorations()
130
+ };
131
+ console.log(final);
132
+ const outputFile = filename || this.filename;
133
+ fs.writeFileSync(outputFile, JSON.stringify(final, null, 4), { encoding: this.encoding });
134
+ }
135
+ }
136
+ //# sourceMappingURL=LevelDict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LevelDict.js","sourceRoot":"","sources":["../src/LevelDict.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=LevelFile.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LevelFile.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/LevelFile.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,73 @@
1
+ import { LevelDict } from '../LevelDict';
2
+ import * as fs from 'fs';
3
+ // Mock fs module
4
+ jest.mock('fs');
5
+ describe('LevelDict', () => {
6
+ beforeEach(() => {
7
+ jest.clearAllMocks();
8
+ });
9
+ it('should create an empty level file when no filename is provided', () => {
10
+ const level = new LevelDict();
11
+ expect(level.getAngles()).toEqual([0]);
12
+ expect(level.getActions()).toEqual([]);
13
+ expect(level.getDecorations()).toEqual([]);
14
+ });
15
+ it('should throw InvalidLevelException for invalid file', () => {
16
+ fs.readFileSync.mockReturnValue('{}');
17
+ expect(() => {
18
+ new LevelDict('invalid.adofai');
19
+ }).toThrow('The provided .adofai file is invalid');
20
+ });
21
+ it('should load a valid level file', () => {
22
+ const mockLevelData = {
23
+ angleData: [0, 90, 180],
24
+ settings: { bpm: 120 },
25
+ actions: [],
26
+ decorations: []
27
+ };
28
+ fs.readFileSync.mockReturnValue(JSON.stringify(mockLevelData));
29
+ const level = new LevelDict('test.adofai');
30
+ expect(level.getAngles()).toEqual([0, 90, 180]);
31
+ });
32
+ it('should write level file correctly', () => {
33
+ const level = new LevelDict();
34
+ level.setAngles([0, 90, 180]);
35
+ level.writeToFile('output.adofai');
36
+ expect(fs.writeFileSync).toHaveBeenCalledWith('output.adofai', expect.stringMatching(/"angleData"\s*:\s*\[\s*0\s*,\s*90\s*,\s*180\s*\]/), { encoding: 'utf-8' });
37
+ });
38
+ it('should handle path-based level data', () => {
39
+ const mockLevelData = {
40
+ pathData: 'RUL',
41
+ settings: { bpm: 120 },
42
+ actions: [],
43
+ decorations: []
44
+ };
45
+ fs.readFileSync.mockReturnValue(JSON.stringify(mockLevelData));
46
+ const level = new LevelDict('test.adofai');
47
+ expect(level.getAngles()).toEqual([0, 90, 180]);
48
+ });
49
+ it('should get relative angles correctly', () => {
50
+ const mockLevelData = {
51
+ angleData: [0, 90, 180, 180],
52
+ settings: { bpm: 120 },
53
+ actions: [],
54
+ decorations: []
55
+ };
56
+ fs.readFileSync.mockReturnValue(JSON.stringify(mockLevelData));
57
+ const level = new LevelDict('test.adofai');
58
+ const relativeAngles = level.getAnglesRelative();
59
+ expect(relativeAngles).toEqual([180, 90, 90, 180]);
60
+ });
61
+ it('should parse malformed parameter sequence', () => {
62
+ const mockBadLevelData = `{
63
+ "pathData": "RURU",
64
+ "settings": { "bpm": 120 },
65
+ "actions": []
66
+ "decorations": []
67
+ }`;
68
+ fs.readFileSync.mockReturnValue(mockBadLevelData);
69
+ const level = new LevelDict('test.adofai');
70
+ expect(level.getAngles()).toEqual([0, 90, 0, 90]);
71
+ });
72
+ });
73
+ //# sourceMappingURL=LevelFile.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LevelFile.test.js","sourceRoot":"","sources":["../../src/__tests__/LevelFile.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export * from './LevelDict';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,18 +1,3 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./LevelDict"), exports);
1
+ export * from './types';
2
+ export * from './LevelDict';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,39 @@
1
+ export interface Action {
2
+ [key: string]: any;
3
+ floor?: number;
4
+ eventType?: string;
5
+ angleOffset?: number;
6
+ }
7
+ export interface Decoration {
8
+ [key: string]: any;
9
+ floor?: number;
10
+ }
11
+ export interface Settings {
12
+ requiredMods?: string[];
13
+ songFilename?: string;
14
+ artist?: string;
15
+ song?: string;
16
+ author?: string;
17
+ difficulty?: string;
18
+ bpm?: string;
19
+ backgroundColor?: string;
20
+ bgImage?: string;
21
+ showDefaultBGIfNoImage?: string;
22
+ zoom?: number;
23
+ [key: string]: any;
24
+ }
25
+ export interface Tile {
26
+ angle: number;
27
+ actions: Action[];
28
+ decorations: Decoration[];
29
+ }
30
+ export interface LevelJSON {
31
+ actions?: Array<Record<string, any>>;
32
+ decorations?: Array<Record<string, any>>;
33
+ settings?: Settings;
34
+ [key: string]: any;
35
+ }
36
+ export declare class InvalidLevelDictException extends Error {
37
+ constructor(message: string);
38
+ }
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAI5B"}
@@ -0,0 +1,7 @@
1
+ export class InvalidLevelDictException extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'InvalidLevelDictException';
5
+ }
6
+ }
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAwCA,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF"}
@@ -1,19 +1,18 @@
1
- import { Settings } from ".";
2
-
3
- export interface LevelJSON {
4
- actions?: Array<Record<string, any>>;
5
- decorations?: Array<Record<string, any>>;
6
- settings?: Settings;
7
- [key: string]: any;
8
- }
9
-
10
- export interface TransformOptions {
11
- keepEventTypes?: Set<string>;
12
- dropEventTypes?: Set<string>;
13
- baseCameraZoom?: number;
14
- extraProtectedEventTypes?: Set<string>;
15
- additionalPatterns?: Set<RegExp>;
16
- constantBackgroundColor?: string;
17
- removeForegroundFlash?: boolean;
18
- dropFilters?: Set<string>;
19
- }
1
+ import { Settings } from ".";
2
+ export interface LevelJSON {
3
+ actions?: Array<Record<string, any>>;
4
+ decorations?: Array<Record<string, any>>;
5
+ settings?: Settings;
6
+ [key: string]: any;
7
+ }
8
+ export interface TransformOptions {
9
+ keepEventTypes?: Set<string>;
10
+ dropEventTypes?: Set<string>;
11
+ baseCameraZoom?: number;
12
+ extraProtectedEventTypes?: Set<string>;
13
+ additionalPatterns?: Set<RegExp>;
14
+ constantBackgroundColor?: string;
15
+ removeForegroundFlash?: boolean;
16
+ dropFilters?: Set<string>;
17
+ }
18
+ //# sourceMappingURL=level.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level.d.ts","sourceRoot":"","sources":["../../src/types/level.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC;AAE7B,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wBAAwB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=level.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level.js","sourceRoot":"","sources":["../../src/types/level.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import { LevelJSON } from '../types/level';
2
+ /**
3
+ * Ensure bad comma handling
4
+ */
5
+ export declare function safeParseJSON(str: string): LevelJSON;
6
+ //# sourceMappingURL=levelUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levelUtils.d.ts","sourceRoot":"","sources":["../../src/utils/levelUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAWhD"}
@@ -0,0 +1,17 @@
1
+ import JSON5 from 'json5';
2
+ /**
3
+ * Ensure bad comma handling
4
+ */
5
+ export function safeParseJSON(str) {
6
+ try {
7
+ const cleaned = str
8
+ .replace(/,(\s*[}\]])/g, '$1') // Remove trailing commas before closing brackets
9
+ .replace(/([}\]])[\s\n]*([}\]])/g, '$1,$2') // Ensure comma between closing brackets
10
+ .replace(/([}\]])[\s\n]*("decorations"|"actions"|"settings")/g, '$1,$2'); // Ensure comma before main sections
11
+ return JSON5.parse(cleaned);
12
+ }
13
+ catch (e) {
14
+ throw new Error('Failed to parse level JSON');
15
+ }
16
+ }
17
+ //# sourceMappingURL=levelUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levelUtils.js","sourceRoot":"","sources":["../../src/utils/levelUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACjC,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,GAAG;aACd,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,iDAAiD;aAC/E,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC,wCAAwC;aACnF,OAAO,CAAC,qDAAqD,EAAE,OAAO,CAAC,CAAC,CAAC,oCAAoC;QAElH,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAClD,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "adofai-lib",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A TypeScript library for working with ADOFAI level files. Original by M1n3c4rt",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
7
12
  "scripts": {
8
13
  "build": "tsc",
9
14
  "test": "jest",
10
- "prepare": "npm run build"
15
+ "prepare": "npm run build",
16
+ "prepublishOnly": "npm test && npm run lint",
17
+ "lint": "gts lint",
18
+ "clean": "rimraf dist"
11
19
  },
12
20
  "keywords": [
13
21
  "adofai",
@@ -21,7 +29,12 @@
21
29
  "@types/jest": "^29.5.12",
22
30
  "@types/node": "^20.11.24",
23
31
  "jest": "^29.7.0",
32
+ "rimraf": "^5.0.5",
24
33
  "ts-jest": "^29.1.2",
25
34
  "typescript": "^5.3.3"
35
+ },
36
+ "dependencies": {
37
+ "gts": "^6.0.2",
38
+ "json5": "^2.2.3"
26
39
  }
27
40
  }
package/jest.config.js DELETED
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- testMatch: ['**/__tests__/**/*.test.ts'],
5
- moduleFileExtensions: ['ts', 'js'],
6
- };
package/src/LevelDict.ts DELETED
@@ -1,165 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as utils from './utils/levelUtils';
3
- import { Action, Decoration, Settings, Tile, InvalidLevelDictException } from './types';
4
- import { LevelJSON } from './types/level';
5
-
6
- export class LevelDict {
7
- private filename: string;
8
- private encoding: BufferEncoding;
9
- private tiles: Tile[];
10
- private nonFloorDecos: Decoration[];
11
- private settings: Settings;
12
-
13
- constructor(filename: string = '', encoding: BufferEncoding = 'utf-8') {
14
- this.filename = filename;
15
- this.encoding = encoding;
16
- this.tiles = [];
17
- this.nonFloorDecos = [];
18
- this.settings = {};
19
-
20
- const leveldict = this.getFileDict(filename);
21
- if (!leveldict.actions || !leveldict.settings || (!leveldict.angleData && !leveldict.pathData)) {
22
- throw new InvalidLevelDictException(`The provided .adofai file is invalid. (missing: ${!leveldict.actions ? 'actions' : ''} ${!leveldict.settings ? 'settings' : ''} ${!leveldict.angleData && !leveldict.pathData ? 'angleData or pathData' : ''})`);
23
- }
24
-
25
- let angleData: number[];
26
- if ('angleData' in leveldict) {
27
- angleData = leveldict.angleData;
28
- } else {
29
- const pathchars: { [key: string]: number } = {
30
- 'R': 0, 'p': 15, 'J': 30, 'E': 45, 'T': 60, 'o': 75, 'U': 90,
31
- 'q': 105, 'G': 120, 'Q': 135, 'H': 150, 'W': 165, 'L': 180,
32
- 'x': 195, 'N': 210, 'Z': 225, 'F': 240, 'V': 255, 'D': 270,
33
- 'Y': 285, 'B': 300, 'C': 315, 'M': 330, 'A': 345, '!': 999
34
- };
35
- angleData = Array.from(leveldict.pathData as string).map(char => pathchars[char]);
36
- }
37
- const actions = leveldict.actions;
38
- const decorations = leveldict.decorations || [];
39
-
40
- this.nonFloorDecos = decorations.filter((j: Decoration) => !('floor' in j)).map((j: Decoration) => ({ ...j }));
41
- this.settings = filename !== '' ? { ...leveldict.settings } : {};
42
-
43
- // Initialize tiles
44
- this.tiles = angleData.map(angle => ({
45
- angle,
46
- actions: [],
47
- decorations: []
48
- }));
49
- console.log('mapping tiles', angleData, this.tiles);
50
- // Add actions
51
- actions.forEach((action: Action) => {
52
- if (action.floor !== undefined && action.floor < this.tiles.length) {
53
- this.tiles[action.floor].actions.push({ ...action });
54
- }
55
- });
56
-
57
- // Add decorations
58
- decorations.forEach((deco: Decoration) => {
59
- if ('floor' in deco) {
60
- if (deco.floor! >= this.tiles.length) {
61
- this.tiles[this.tiles.length - 1].decorations.push({ ...deco });
62
- } else {
63
- this.tiles[deco.floor!].decorations.push({ ...deco });
64
- }
65
- }
66
- });
67
- }
68
-
69
- private getFileString(filename: string): string {
70
- if (!filename) return '';
71
- return fs.readFileSync(filename, { encoding: this.encoding });
72
- }
73
-
74
- private getFileDict(filename: string): LevelJSON {
75
- if (!filename) {
76
- return {
77
- angleData: [0],
78
- settings: {},
79
- actions: [],
80
- decorations: []
81
- };
82
- }
83
-
84
- const content = this.getFileString(filename);
85
- return utils.safeParseJSON(content);
86
- }
87
-
88
- public getAngles(): number[] {
89
- return this.tiles.map(tile => tile.angle);
90
- }
91
-
92
- public setAngles(angles: number[]): void {
93
- while (angles.length > this.tiles.length) {
94
- this.tiles.push({
95
- angle: angles[this.tiles.length],
96
- actions: [],
97
- decorations: []
98
- });
99
- }
100
- this.tiles = this.tiles.slice(0, angles.length);
101
- this.tiles.forEach((tile, i) => {
102
- tile.angle = angles[i];
103
- });
104
- }
105
-
106
- public getAnglesRelative(ignoreTwirls: boolean = false, padMidspins: boolean = false): number[] {
107
- const absangles = this.getAngles();
108
-
109
- if (!ignoreTwirls) {
110
- const twirls = this.getActions(action => action.eventType === 'Twirl')
111
- .map(event => event.floor!);
112
-
113
- for (const twirl of twirls.reverse()) {
114
- absangles.splice(twirl, absangles.length - twirl,
115
- ...absangles.slice(twirl).map(angle =>
116
- angle !== 999 ? (2 * absangles[twirl - 1] - angle) % 360 : 999
117
- )
118
- );
119
- }
120
- }
121
-
122
- const midspins = absangles.map((angle, idx) => angle === 999 ? idx : -1).filter(idx => idx !== -1);
123
- for (const midspin of midspins.reverse()) {
124
- absangles.splice(midspin + 1, absangles.length - (midspin + 1),
125
- ...absangles.slice(midspin + 1).map(angle =>
126
- angle !== 999 ? (angle + 180) % 360 : 999
127
- )
128
- );
129
- }
130
-
131
- if (!padMidspins) {
132
- absangles.splice(0, absangles.length, ...absangles.filter(angle => angle !== 999));
133
- }
134
-
135
- return absangles.map((angle, idx) => {
136
- if (angle === 999) return 0;
137
- if (idx === 0) return ((0 - angle + 180 - 1) % 360) + 1;
138
- if (absangles[idx - 1] === 999) {
139
- return ((absangles[idx - 2] - angle + 180 - 1) % 360) + 1;
140
- }
141
- return ((absangles[idx - 1] - angle + 180 - 1) % 360) + 1;
142
- });
143
- }
144
-
145
- public getActions(condition: (action: Action) => boolean = () => true): Action[] {
146
- return this.tiles.flatMap(tile => tile.actions.filter(condition));
147
- }
148
-
149
- public getDecorations(condition: (decoration: Decoration) => boolean = () => true): Decoration[] {
150
- return this.tiles.flatMap(tile => tile.decorations.filter(condition))
151
- .concat(this.nonFloorDecos.filter(condition));
152
- }
153
-
154
- public writeToFile(filename?: string): void {
155
- const final = {
156
- angleData: this.getAngles(),
157
- settings: { ...this.settings },
158
- actions: this.getActions(),
159
- decorations: this.getDecorations()
160
- };
161
- console.log(final);
162
- const outputFile = filename || this.filename;
163
- fs.writeFileSync(outputFile, JSON.stringify(final, null, 4), { encoding: this.encoding });
164
- }
165
- }
@@ -1,94 +0,0 @@
1
- import { LevelDict } from '../LevelDict';
2
- import * as fs from 'fs';
3
-
4
- // Mock fs module
5
- jest.mock('fs');
6
-
7
- describe('LevelDict', () => {
8
- beforeEach(() => {
9
- jest.clearAllMocks();
10
- });
11
-
12
- it('should create an empty level file when no filename is provided', () => {
13
- const level = new LevelDict();
14
- expect(level.getAngles()).toEqual([0]);
15
- expect(level.getActions()).toEqual([]);
16
- expect(level.getDecorations()).toEqual([]);
17
- });
18
-
19
- it('should throw InvalidLevelException for invalid file', () => {
20
- (fs.readFileSync as jest.Mock).mockReturnValue('{}');
21
-
22
- expect(() => {
23
- new LevelDict('invalid.adofai');
24
- }).toThrow('The provided .adofai file is invalid');
25
- });
26
-
27
- it('should load a valid level file', () => {
28
- const mockLevelData = {
29
- angleData: [0, 90, 180],
30
- settings: { bpm: 120 },
31
- actions: [],
32
- decorations: []
33
- };
34
-
35
- (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockLevelData));
36
-
37
- const level = new LevelDict('test.adofai');
38
- expect(level.getAngles()).toEqual([0, 90, 180]);
39
- });
40
-
41
- it('should write level file correctly', () => {
42
- const level = new LevelDict();
43
- level.setAngles([0, 90, 180]);
44
-
45
- level.writeToFile('output.adofai');
46
-
47
- expect(fs.writeFileSync).toHaveBeenCalledWith(
48
- 'output.adofai',
49
- expect.stringMatching(/"angleData"\s*:\s*\[\s*0\s*,\s*90\s*,\s*180\s*\]/),
50
- { encoding: 'utf-8' }
51
- );
52
- });
53
-
54
- it('should handle path-based level data', () => {
55
- const mockLevelData = {
56
- pathData: 'RUL',
57
- settings: { bpm: 120 },
58
- actions: [],
59
- decorations: []
60
- };
61
-
62
- (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockLevelData));
63
-
64
- const level = new LevelDict('test.adofai');
65
- expect(level.getAngles()).toEqual([0, 90, 180]);
66
- });
67
-
68
- it('should get relative angles correctly', () => {
69
- const mockLevelData = {
70
- angleData: [0, 90, 180, 180],
71
- settings: { bpm: 120 },
72
- actions: [],
73
- decorations: []
74
- };
75
-
76
- (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockLevelData));
77
-
78
- const level = new LevelDict('test.adofai');
79
- const relativeAngles = level.getAnglesRelative();
80
- expect(relativeAngles).toEqual([180, 90, 90, 180]);
81
- });
82
-
83
- it('should parse malformed parameter sequence', () => {
84
- const mockBadLevelData = `{
85
- "pathData": "RURU",
86
- "settings": { "bpm": 120 },
87
- "actions": []
88
- "decorations": []
89
- }`;
90
- (fs.readFileSync as jest.Mock).mockReturnValue(mockBadLevelData);
91
- const level = new LevelDict('test.adofai');
92
- expect(level.getAngles()).toEqual([0, 90, 0, 90]);
93
- });
94
- });
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './types';
2
- export * from './LevelDict';
@@ -1,28 +0,0 @@
1
- export interface Action {
2
- [key: string]: any;
3
- floor?: number;
4
- eventType?: string;
5
- angleOffset?: number;
6
- }
7
-
8
- export interface Decoration {
9
- [key: string]: any;
10
- floor?: number;
11
- }
12
-
13
- export interface Settings {
14
- [key: string]: any;
15
- }
16
-
17
- export interface Tile {
18
- angle: number;
19
- actions: Action[];
20
- decorations: Decoration[];
21
- }
22
-
23
- export class InvalidLevelDictException extends Error {
24
- constructor(message: string) {
25
- super(message);
26
- this.name = 'InvalidLevelDictException';
27
- }
28
- }
@@ -1,18 +0,0 @@
1
- import JSON5 from 'json5';
2
- import { LevelJSON } from '../types/level';
3
-
4
- /**
5
- * Ensure bad comma handling
6
- */
7
- export function safeParseJSON(str: string): LevelJSON {
8
- try {
9
- const cleaned = str
10
- .replace(/,(\s*[}\]])/g, '$1') // Remove trailing commas before closing brackets
11
- .replace(/([}\]])[\s\n]*([}\]])/g, '$1,$2') // Ensure comma between closing brackets
12
- .replace(/([}\]])[\s\n]*("decorations"|"actions"|"settings")/g, '$1,$2'); // Ensure comma before main sections
13
-
14
- return JSON5.parse(cleaned);
15
- } catch (e) {
16
- throw new Error('Failed to parse level JSON');
17
- }
18
- }
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2019",
4
- "module": "commonjs",
5
- "declaration": true,
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "moduleResolution": "node",
13
- "lib": ["es2019", "dom"],
14
- "composite": false
15
- },
16
- "include": ["src/**/*"],
17
- "exclude": ["node_modules", "dist", "**/*.test.ts"]
18
- }