sonolus-voez-engine 1.0.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/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 NonSpicyBurrito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Sonolus VOEZ Engine
2
+
3
+ A recreation of VOEZ engine in [Sonolus](https://sonolus.com).
4
+
5
+ ## Links
6
+
7
+ - [Sonolus Website](https://sonolus.com)
8
+ - [Sonolus Wiki](https://github.com/NonSpicyBurrito/sonolus-wiki)
9
+
10
+ ## Installation
11
+
12
+ ```
13
+ npm install sonolus-voez-engine
14
+ ```
15
+
16
+ ## Custom Resources
17
+
18
+ ### Skin Sprites
19
+
20
+ | Name |
21
+ | ------------------------------ |
22
+ | `VOEZ Track Body 0` |
23
+ | `VOEZ Track Body 1` |
24
+ | `VOEZ Track Body 2` |
25
+ | `VOEZ Track Body 3` |
26
+ | `VOEZ Track Body 4` |
27
+ | `VOEZ Track Body 5` |
28
+ | `VOEZ Track Body 6` |
29
+ | `VOEZ Track Body 7` |
30
+ | `VOEZ Track Body 8` |
31
+ | `VOEZ Track Body 9` |
32
+ | `VOEZ Track Line` |
33
+ | `VOEZ Track Left Border` |
34
+ | `VOEZ Track Right Border` |
35
+ | `VOEZ Track Glow Body` |
36
+ | `VOEZ Track Glow Left Border` |
37
+ | `VOEZ Track Glow Right Border` |
38
+ | `VOEZ Flick` |
39
+
40
+ ## Documentation
41
+
42
+ ### `version`
43
+
44
+ Package version.
45
+
46
+ ### `engineInfo`
47
+
48
+ Partial engine information compatible with [sonolus-express](https://github.com/NonSpicyBurrito/sonolus-express).
49
+
50
+ ### `engineConfiguration`
51
+
52
+ Engine Configuration.
53
+
54
+ - `engineConfiguration.path`: path to file.
55
+ - `engineConfiguration.buffer`: buffer of file.
56
+ - `engineConfiguration.hash`: hash of file.
57
+
58
+ ### `engineData`
59
+
60
+ Engine Data.
61
+
62
+ - `engineData.path`: path to file.
63
+ - `engineData.buffer`: buffer of file.
64
+ - `engineData.hash`: hash of file.
65
+
66
+ ### `engineThumbnail`
67
+
68
+ Engine Thumbnail.
69
+
70
+ - `engineThumbnail.path`: path to file.
71
+ - `engineThumbnail.buffer`: buffer of file.
72
+ - `engineThumbnail.hash`: hash of file.
73
+
74
+ ### `vsToVC(vs)`
75
+
76
+ Converts VS (VOEZ Source) to VC (VOEZ Chart).
77
+
78
+ - `vs`: VOEZ source.
79
+
80
+ ### `vcToLevelData(vc, offset?)`
81
+
82
+ Converts VC (VOEZ Chart) to Level Data.
83
+
84
+ - `vc`: VOEZ chart.
85
+ - `offset`: offset (default: `0`).
Binary file
Binary file
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Resource = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ class Resource {
8
+ constructor(path) {
9
+ this.path = (0, node_path_1.resolve)(__dirname, path);
10
+ }
11
+ get hash() {
12
+ this._hash ??= (0, node_crypto_1.createHash)('sha1').update(this.buffer).digest('hex');
13
+ return this._hash;
14
+ }
15
+ get buffer() {
16
+ this._buffer ??= (0, node_fs_1.readFileSync)(this.path);
17
+ return this._buffer;
18
+ }
19
+ }
20
+ exports.Resource = Resource;
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ export declare class Resource {
3
+ readonly path: string;
4
+ private _hash?;
5
+ private _buffer?;
6
+ constructor(path: string);
7
+ get hash(): string;
8
+ get buffer(): Buffer;
9
+ }
package/dist/index.cjs ADDED
@@ -0,0 +1,52 @@
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
+ exports.engineThumbnail = exports.engineData = exports.engineConfiguration = exports.engineInfo = exports.version = exports.vsToVC = exports.vcToLevelData = void 0;
18
+ const Resource_cjs_1 = require("./Resource.cjs");
19
+ var convert_cjs_1 = require("./vc/convert.cjs");
20
+ Object.defineProperty(exports, "vcToLevelData", { enumerable: true, get: function () { return convert_cjs_1.vcToLevelData; } });
21
+ __exportStar(require("./vc/index.cjs"), exports);
22
+ var convert_cjs_2 = require("./vs/convert.cjs");
23
+ Object.defineProperty(exports, "vsToVC", { enumerable: true, get: function () { return convert_cjs_2.vsToVC; } });
24
+ __exportStar(require("./vs/index.cjs"), exports);
25
+ exports.version = '1.0.0';
26
+ exports.engineInfo = {
27
+ name: 'voez',
28
+ version: 8,
29
+ title: {
30
+ en: 'VOEZ',
31
+ },
32
+ subtitle: {
33
+ en: 'VOEZ',
34
+ },
35
+ author: {
36
+ en: 'Burrito',
37
+ },
38
+ description: {
39
+ en: [
40
+ 'A recreation of VOEZ engine in Sonolus.',
41
+ '',
42
+ 'Version:',
43
+ exports.version,
44
+ '',
45
+ 'GitHub Repository:',
46
+ 'https://github.com/NonSpicyBurrito/sonolus-voez-engine',
47
+ ].join('\n'),
48
+ },
49
+ };
50
+ exports.engineConfiguration = new Resource_cjs_1.Resource('EngineConfiguration');
51
+ exports.engineData = new Resource_cjs_1.Resource('EngineData');
52
+ exports.engineThumbnail = new Resource_cjs_1.Resource('thumbnail.png');
@@ -0,0 +1,25 @@
1
+ import { Resource } from './Resource.cjs';
2
+ export { vcToLevelData } from './vc/convert.cjs';
3
+ export * from './vc/index.cjs';
4
+ export { vsToVC } from './vs/convert.cjs';
5
+ export * from './vs/index.cjs';
6
+ export declare const version = "1.0.0";
7
+ export declare const engineInfo: {
8
+ readonly name: "voez";
9
+ readonly version: 8;
10
+ readonly title: {
11
+ readonly en: "VOEZ";
12
+ };
13
+ readonly subtitle: {
14
+ readonly en: "VOEZ";
15
+ };
16
+ readonly author: {
17
+ readonly en: "Burrito";
18
+ };
19
+ readonly description: {
20
+ readonly en: string;
21
+ };
22
+ };
23
+ export declare const engineConfiguration: Resource;
24
+ export declare const engineData: Resource;
25
+ export declare const engineThumbnail: Resource;
Binary file
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vcToLevelData = void 0;
4
+ const sonolus_core_1 = require("sonolus-core");
5
+ const ease = [
6
+ 'InSine',
7
+ 'OutSine',
8
+ 'InOutSine',
9
+ 'OutInSine',
10
+ 'InQuad',
11
+ 'OutQuad',
12
+ 'InOutQuad',
13
+ 'OutInQuad',
14
+ 'InCubic',
15
+ 'OutCubic',
16
+ 'InOutCubic',
17
+ 'OutInCubic',
18
+ 'InQuart',
19
+ 'OutQuart',
20
+ 'InOutQuart',
21
+ 'OutInQuart',
22
+ 'InQuint',
23
+ 'OutQuint',
24
+ 'InOutQuint',
25
+ 'OutInQuint',
26
+ 'InExpo',
27
+ 'OutExpo',
28
+ 'InOutExpo',
29
+ 'OutInExpo',
30
+ 'InCirc',
31
+ 'OutCirc',
32
+ 'InOutCirc',
33
+ 'OutInCirc',
34
+ 'InBack',
35
+ 'OutBack',
36
+ 'InOutBack',
37
+ 'OutInBack',
38
+ 'InElastic',
39
+ 'OutElastic',
40
+ 'InOutElastic',
41
+ 'OutInElastic',
42
+ ];
43
+ const vcToLevelData = (vc, offset = 0) => {
44
+ const entities = [
45
+ {
46
+ archetype: 'Initialization',
47
+ data: [],
48
+ },
49
+ {
50
+ archetype: 'InputManager',
51
+ data: [],
52
+ },
53
+ {
54
+ archetype: 'Stage',
55
+ data: [],
56
+ },
57
+ ];
58
+ const add = (entity) => entities.push({
59
+ ...entity,
60
+ data: Object.entries(entity.data).map(([k, v]) => typeof v === 'number' ? { name: k, value: v } : { name: k, ref: v }),
61
+ });
62
+ let id = 0;
63
+ const next = () => `${id++}`;
64
+ for (const bpm of vc.bpms) {
65
+ add({
66
+ archetype: sonolus_core_1.EngineArchetypeName.BpmChange,
67
+ data: {
68
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: bpm.beat,
69
+ [sonolus_core_1.EngineArchetypeDataName.Bpm]: bpm.bpm,
70
+ },
71
+ });
72
+ }
73
+ for (const track of vc.tracks) {
74
+ const ref = next();
75
+ add({
76
+ ref,
77
+ archetype: 'Track',
78
+ data: {
79
+ x: track.x,
80
+ w: track.w,
81
+ c: track.c,
82
+ startBeat: track.startBeat,
83
+ endBeat: track.endBeat,
84
+ animateStart: +track.animateStart,
85
+ },
86
+ });
87
+ const addCommand = (archetype, command) => add({
88
+ archetype,
89
+ data: {
90
+ trackRef: ref,
91
+ startBeat: command.startBeat,
92
+ startValue: command.startValue,
93
+ endBeat: command.endBeat,
94
+ endValue: command.endValue,
95
+ ease: ease.indexOf(command.ease),
96
+ },
97
+ });
98
+ for (const command of track.moveCommands) {
99
+ addCommand('TrackMoveCommand', command);
100
+ }
101
+ for (const command of track.scaleCommands) {
102
+ addCommand('TrackScaleCommand', command);
103
+ }
104
+ for (const command of track.colorCommands) {
105
+ addCommand('TrackColorCommand', command);
106
+ }
107
+ for (const note of track.notes) {
108
+ switch (note.type) {
109
+ case 'tap':
110
+ add({
111
+ archetype: 'TapNote',
112
+ data: {
113
+ trackRef: ref,
114
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: note.beat,
115
+ },
116
+ });
117
+ break;
118
+ case 'slide':
119
+ add({
120
+ archetype: 'SlideNote',
121
+ data: {
122
+ trackRef: ref,
123
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: note.beat,
124
+ },
125
+ });
126
+ break;
127
+ case 'flick':
128
+ add({
129
+ archetype: 'FlickNote',
130
+ data: {
131
+ trackRef: ref,
132
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: note.beat,
133
+ direction: note.direction === 'left' ? -1 : 1,
134
+ },
135
+ });
136
+ break;
137
+ case 'hold': {
138
+ const headRef = next();
139
+ const tailRef = next();
140
+ add({
141
+ ref: headRef,
142
+ archetype: 'HoldStartNote',
143
+ data: {
144
+ trackRef: ref,
145
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: note.beat,
146
+ },
147
+ });
148
+ add({
149
+ ref: tailRef,
150
+ archetype: 'HoldEndNote',
151
+ data: {
152
+ trackRef: ref,
153
+ [sonolus_core_1.EngineArchetypeDataName.Beat]: note.toBeat,
154
+ headRef,
155
+ },
156
+ });
157
+ add({
158
+ archetype: 'HoldConnector',
159
+ data: {
160
+ headRef,
161
+ tailRef,
162
+ },
163
+ });
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ return {
170
+ bgmOffset: offset,
171
+ entities,
172
+ };
173
+ };
174
+ exports.vcToLevelData = vcToLevelData;
@@ -0,0 +1,3 @@
1
+ import { LevelData } from 'sonolus-core';
2
+ import { VC } from './index.cjs';
3
+ export declare const vcToLevelData: (vc: VC, offset?: number) => LevelData;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,46 @@
1
+ export type VC = {
2
+ bpms: VCBpm[];
3
+ tracks: VCTrack[];
4
+ };
5
+ export type VCBpm = {
6
+ beat: number;
7
+ bpm: number;
8
+ };
9
+ export type VCTrack = {
10
+ x: number;
11
+ w: number;
12
+ c: number;
13
+ startBeat: number;
14
+ endBeat: number;
15
+ animateStart: boolean;
16
+ moveCommands: VCTrackCommand[];
17
+ scaleCommands: VCTrackCommand[];
18
+ colorCommands: VCTrackCommand[];
19
+ notes: VCNote[];
20
+ };
21
+ export type VCTrackCommand = {
22
+ startBeat: number;
23
+ startValue: number;
24
+ endBeat: number;
25
+ endValue: number;
26
+ ease: string;
27
+ };
28
+ export type VCNote = VCTapNote | VCSlideNote | VCFlickNote | VCHoldNote;
29
+ type BaseVCNote = {
30
+ beat: number;
31
+ };
32
+ export type VCTapNote = BaseVCNote & {
33
+ type: 'tap';
34
+ };
35
+ export type VCSlideNote = BaseVCNote & {
36
+ type: 'slide';
37
+ };
38
+ export type VCFlickNote = BaseVCNote & {
39
+ type: 'flick';
40
+ direction: 'left' | 'right';
41
+ };
42
+ export type VCHoldNote = BaseVCNote & {
43
+ type: 'hold';
44
+ toBeat: number;
45
+ };
46
+ export {};
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vsToVC = void 0;
4
+ const easeMap = {
5
+ easeinsine: 'InSine',
6
+ easeoutsine: 'OutSine',
7
+ easeinoutsine: 'InOutSine',
8
+ easeoutinsine: 'OutInSine',
9
+ easeinquad: 'InQuad',
10
+ easeoutquad: 'OutQuad',
11
+ easeinoutquad: 'InOutQuad',
12
+ easeoutinquad: 'OutInQuad',
13
+ easeincubic: 'InCubic',
14
+ easeoutcubic: 'OutCubic',
15
+ easeinoutcubic: 'InOutCubic',
16
+ easeoutincubic: 'OutInCubic',
17
+ easeinquart: 'InQuart',
18
+ easeoutquart: 'OutQuart',
19
+ easeinoutquart: 'InOutQuart',
20
+ easeoutinquart: 'OutInQuart',
21
+ easeinquint: 'InQuint',
22
+ easeoutquint: 'OutQuint',
23
+ easeinoutquint: 'InOutQuint',
24
+ easeoutinquint: 'OutInQuint',
25
+ easeinexpo: 'InExpo',
26
+ easeoutexpo: 'OutExpo',
27
+ easeinoutexpo: 'InOutExpo',
28
+ easeoutinexpo: 'OutInExpo',
29
+ easeincirc: 'InCirc',
30
+ easeoutcirc: 'OutCirc',
31
+ easeinoutcirc: 'InOutCirc',
32
+ easeoutincirc: 'OutInCirc',
33
+ easeinback: 'InBack',
34
+ easeoutback: 'OutBack',
35
+ easeinoutback: 'InOutBack',
36
+ easeoutinback: 'OutInBack',
37
+ easeinelastic: 'InElastic',
38
+ easeintelastic: 'InElastic',
39
+ easeoutelastic: 'OutElastic',
40
+ easeinoutelastic: 'InOutElastic',
41
+ easeoutinelastic: 'OutInElastic',
42
+ };
43
+ const vsToVC = (vs) => {
44
+ const vc = {
45
+ bpms: [
46
+ {
47
+ beat: 0,
48
+ bpm: 60,
49
+ },
50
+ ],
51
+ tracks: [],
52
+ };
53
+ const x = (pos) => (pos * 2 - 1) * 7.29;
54
+ const w = (size) => size;
55
+ const c = (color) => color;
56
+ const ease = (ease) => easeMap[ease] ?? 'Linear';
57
+ for (const track of vs.tracks) {
58
+ let lastX = x(track.X);
59
+ let lastW = w(track.Size);
60
+ let lastC = c(track.Color);
61
+ vc.tracks.push({
62
+ x: lastX,
63
+ w: lastW,
64
+ c: lastC,
65
+ startBeat: track.Start,
66
+ endBeat: track.End,
67
+ animateStart: track.EntranceOn,
68
+ moveCommands: track.Move.map((command) => {
69
+ const startValue = lastX;
70
+ const endValue = x(command.To);
71
+ lastX = endValue;
72
+ return {
73
+ startBeat: command.Start,
74
+ startValue,
75
+ endBeat: command.End,
76
+ endValue,
77
+ ease: ease(command.Ease),
78
+ };
79
+ }),
80
+ scaleCommands: track.Scale.map((command) => {
81
+ const startValue = lastW;
82
+ const endValue = w(command.To);
83
+ lastW = endValue;
84
+ return {
85
+ startBeat: command.Start,
86
+ startValue,
87
+ endBeat: command.End,
88
+ endValue,
89
+ ease: ease(command.Ease),
90
+ };
91
+ }),
92
+ colorCommands: track.ColorChange.map((command) => {
93
+ const startValue = lastC;
94
+ const endValue = c(command.To);
95
+ lastC = endValue;
96
+ return {
97
+ startBeat: command.Start,
98
+ startValue,
99
+ endBeat: command.End,
100
+ endValue,
101
+ ease: ease(command.Ease),
102
+ };
103
+ }),
104
+ notes: vs.notes
105
+ .filter((note) => note.Track === track.Id)
106
+ .map((note) => {
107
+ switch (note.Type) {
108
+ case 'click':
109
+ return {
110
+ type: 'tap',
111
+ beat: note.Time,
112
+ };
113
+ case 'slide':
114
+ return {
115
+ type: 'slide',
116
+ beat: note.Time,
117
+ };
118
+ case 'swipe':
119
+ return {
120
+ type: 'flick',
121
+ beat: note.Time,
122
+ direction: note.Dir ? 'right' : 'left',
123
+ };
124
+ case 'hold':
125
+ return {
126
+ type: 'hold',
127
+ beat: note.Time,
128
+ toBeat: note.Time + note.Hold,
129
+ };
130
+ }
131
+ }),
132
+ });
133
+ }
134
+ return vc;
135
+ };
136
+ exports.vsToVC = vsToVC;
@@ -0,0 +1,3 @@
1
+ import { VC } from '../vc/index.cjs';
2
+ import { VS } from './index.cjs';
3
+ export declare const vsToVC: (vs: VS) => VC;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,29 @@
1
+ export type VS = {
2
+ notes: VSNote[];
3
+ tracks: VSTrack[];
4
+ };
5
+ export type VSTrack = {
6
+ Id: number;
7
+ EntranceOn: boolean;
8
+ X: number;
9
+ Size: number;
10
+ Start: number;
11
+ End: number;
12
+ Color: number;
13
+ Move: VSTrackCommand[];
14
+ Scale: VSTrackCommand[];
15
+ ColorChange: VSTrackCommand[];
16
+ };
17
+ export type VSTrackCommand = {
18
+ To: number;
19
+ Ease: string;
20
+ Start: number;
21
+ End: number;
22
+ };
23
+ export type VSNote = {
24
+ Type: 'click' | 'hold' | 'slide' | 'swipe';
25
+ Track: number;
26
+ Time: number;
27
+ Hold: number;
28
+ Dir: 0 | 1;
29
+ };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "sonolus-voez-engine",
3
+ "version": "1.0.0",
4
+ "description": "A recreation of VOEZ engine in Sonolus",
5
+ "author": "NonSpicyBurrito",
6
+ "repository": "github:NonSpicyBurrito/sonolus-voez-engine",
7
+ "license": "MIT",
8
+ "keywords": [
9
+ "Sonolus"
10
+ ],
11
+ "main": "dist/index.cjs",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "dev": "sonolus-cli --dev",
17
+ "prebuild": "tsc -p . --noEmit && eslint --ext .mts ./src && eslint --ext .cts ./lib",
18
+ "build": "tsc -p ./lib/tsconfig.json && sonolus-cli --build && node ./lib/build.mjs"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^16.18.36",
22
+ "@typescript-eslint/eslint-plugin": "^5.59.11",
23
+ "@typescript-eslint/parser": "^5.59.11",
24
+ "eslint": "^8.42.0",
25
+ "eslint-config-prettier": "^8.8.0",
26
+ "eslint-plugin-prettier": "^4.2.1",
27
+ "prettier": "^2.8.8",
28
+ "prettier-plugin-organize-imports": "^3.2.2",
29
+ "sonolus-core": "~7.0.0",
30
+ "sonolus.js": "~9.0.0",
31
+ "typescript": "~5.1.3"
32
+ }
33
+ }