sonolus-next-rush-plus-engine 1.3.3 → 1.3.4-kizuruki
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/dist/EnginePlayData +0 -0
- package/dist/EngineWatchData +0 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +50 -3
- package/dist/mmw/analyze.d.ts +101 -0
- package/dist/mmw/analyze.js +212 -0
- package/dist/mmw/convert.d.ts +9 -0
- package/dist/mmw/convert.js +161 -0
- package/dist/usc/convert.js +12 -12
- package/package.json +2 -1
package/dist/EnginePlayData
CHANGED
|
Binary file
|
package/dist/EngineWatchData
CHANGED
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { LevelData } from '@sonolus/core';
|
|
2
|
+
import { mmwsToUSC } from './mmw/convert.js';
|
|
3
|
+
import { susToUSC } from './sus/convert.js';
|
|
4
|
+
import { uscToLevelData } from './usc/convert.js';
|
|
5
|
+
import { USC } from './usc/index.js';
|
|
6
|
+
export { susToUSC, mmwsToUSC, uscToLevelData };
|
|
3
7
|
export * from './usc/index.js';
|
|
4
|
-
export declare const
|
|
8
|
+
export declare const convertToLevelData: (input: string | Uint8Array | USC | LevelData, offset?: number) => LevelData;
|
|
9
|
+
export declare const version = "1.3.4-kizuruki";
|
|
5
10
|
export declare const databaseEngineItem: {
|
|
6
11
|
readonly name: "next-rush-plus";
|
|
7
12
|
readonly version: 13;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { mmwsToUSC } from './mmw/convert.js';
|
|
2
|
+
import { susToUSC } from './sus/convert.js';
|
|
3
|
+
import { uscToLevelData } from './usc/convert.js';
|
|
4
|
+
export { susToUSC, mmwsToUSC, uscToLevelData };
|
|
3
5
|
export * from './usc/index.js';
|
|
4
|
-
export const
|
|
6
|
+
export const convertToLevelData = (input, offset = 0) => {
|
|
7
|
+
if (isLevelData(input)) {
|
|
8
|
+
return input;
|
|
9
|
+
}
|
|
10
|
+
let usc;
|
|
11
|
+
if (isUSC(input)) {
|
|
12
|
+
usc = input;
|
|
13
|
+
}
|
|
14
|
+
else if (input instanceof Uint8Array) {
|
|
15
|
+
usc = mmwsToUSC(input);
|
|
16
|
+
}
|
|
17
|
+
else if (typeof input === 'string') {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(input);
|
|
20
|
+
if (isLevelData(parsed)) {
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
if (isUSC(parsed)) {
|
|
24
|
+
usc = parsed;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
usc = susToUSC(input);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
usc = susToUSC(input);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw new Error('Unsupported input type: Input must be string(SUS/USC/LevelData), Uint8Array(MMWS), or USC/LevelData object.');
|
|
36
|
+
}
|
|
37
|
+
return uscToLevelData(usc, offset);
|
|
38
|
+
};
|
|
39
|
+
function isUSC(data) {
|
|
40
|
+
return (typeof data === 'object' &&
|
|
41
|
+
data !== null &&
|
|
42
|
+
'objects' in data &&
|
|
43
|
+
Array.isArray(data.objects));
|
|
44
|
+
}
|
|
45
|
+
function isLevelData(data) {
|
|
46
|
+
return (typeof data === 'object' &&
|
|
47
|
+
data !== null &&
|
|
48
|
+
'entities' in data &&
|
|
49
|
+
Array.isArray(data.entities));
|
|
50
|
+
}
|
|
51
|
+
export const version = '1.3.4-kizuruki';
|
|
5
52
|
export const databaseEngineItem = {
|
|
6
53
|
name: 'next-rush-plus',
|
|
7
54
|
version: 13,
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
declare const FlickType: readonly ["none", "up", "left", "right"];
|
|
2
|
+
type FlickType = (typeof FlickType)[number];
|
|
3
|
+
declare const StepType: readonly ["visible", "hidden", "ignored"];
|
|
4
|
+
type StepType = (typeof StepType)[number];
|
|
5
|
+
declare const EaseType: readonly ["linear", "easeIn", "easeOut", "easeInOut", "easeOutIn"];
|
|
6
|
+
export type EaseType = (typeof EaseType)[number];
|
|
7
|
+
export type Score = {
|
|
8
|
+
metadata: {
|
|
9
|
+
title: string;
|
|
10
|
+
author: string;
|
|
11
|
+
artist: string;
|
|
12
|
+
musicFile: string;
|
|
13
|
+
musicOffset: number;
|
|
14
|
+
jacketFile: string;
|
|
15
|
+
};
|
|
16
|
+
events: {
|
|
17
|
+
timeSignatures: {
|
|
18
|
+
measure: number;
|
|
19
|
+
numerator: number;
|
|
20
|
+
denominator: number;
|
|
21
|
+
}[];
|
|
22
|
+
bpmChanges: {
|
|
23
|
+
tick: number;
|
|
24
|
+
bpm: number;
|
|
25
|
+
}[];
|
|
26
|
+
hispeedChanges: {
|
|
27
|
+
tick: number;
|
|
28
|
+
speed: number;
|
|
29
|
+
layer: number;
|
|
30
|
+
}[];
|
|
31
|
+
skills: number[];
|
|
32
|
+
fever: {
|
|
33
|
+
start: number;
|
|
34
|
+
end: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
taps: {
|
|
38
|
+
tick: number;
|
|
39
|
+
lane: number;
|
|
40
|
+
width: number;
|
|
41
|
+
flickType: FlickType;
|
|
42
|
+
flags: {
|
|
43
|
+
critical: boolean;
|
|
44
|
+
friction: boolean;
|
|
45
|
+
};
|
|
46
|
+
layer: number;
|
|
47
|
+
}[];
|
|
48
|
+
holds: {
|
|
49
|
+
flags: {
|
|
50
|
+
startHidden: boolean;
|
|
51
|
+
endHidden: boolean;
|
|
52
|
+
guide: boolean;
|
|
53
|
+
};
|
|
54
|
+
start: {
|
|
55
|
+
tick: number;
|
|
56
|
+
lane: number;
|
|
57
|
+
width: number;
|
|
58
|
+
flags: {
|
|
59
|
+
critical: boolean;
|
|
60
|
+
friction: boolean;
|
|
61
|
+
};
|
|
62
|
+
layer: number;
|
|
63
|
+
ease: EaseType;
|
|
64
|
+
};
|
|
65
|
+
fadeType: number;
|
|
66
|
+
guideColor: number;
|
|
67
|
+
steps: {
|
|
68
|
+
tick: number;
|
|
69
|
+
lane: number;
|
|
70
|
+
width: number;
|
|
71
|
+
type: StepType;
|
|
72
|
+
ease: EaseType;
|
|
73
|
+
layer: number;
|
|
74
|
+
}[];
|
|
75
|
+
end: {
|
|
76
|
+
tick: number;
|
|
77
|
+
lane: number;
|
|
78
|
+
width: number;
|
|
79
|
+
flickType: FlickType;
|
|
80
|
+
flags: {
|
|
81
|
+
critical: boolean;
|
|
82
|
+
friction: boolean;
|
|
83
|
+
};
|
|
84
|
+
layer: number;
|
|
85
|
+
};
|
|
86
|
+
}[];
|
|
87
|
+
damages: {
|
|
88
|
+
tick: number;
|
|
89
|
+
lane: number;
|
|
90
|
+
width: number;
|
|
91
|
+
flickType: FlickType;
|
|
92
|
+
flags: {
|
|
93
|
+
critical: boolean;
|
|
94
|
+
friction: boolean;
|
|
95
|
+
};
|
|
96
|
+
layer: number;
|
|
97
|
+
}[];
|
|
98
|
+
numLayers: number;
|
|
99
|
+
};
|
|
100
|
+
export declare const analyze: (mmws: Uint8Array) => Score;
|
|
101
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import BinarySeeker from '@sevenc-nanashi/binaryseeker';
|
|
2
|
+
const FlickType = ['none', 'up', 'left', 'right'];
|
|
3
|
+
const StepType = ['visible', 'hidden', 'ignored'];
|
|
4
|
+
const EaseType = ['linear', 'easeIn', 'easeOut', 'easeInOut', 'easeOutIn'];
|
|
5
|
+
export const analyze = (mmws) => {
|
|
6
|
+
const buffer = new BinarySeeker(mmws.buffer);
|
|
7
|
+
const header = buffer.readString();
|
|
8
|
+
if (header !== 'MMWS' && header !== 'CCMMWS') {
|
|
9
|
+
throw new Error('Invalid MMWS file');
|
|
10
|
+
}
|
|
11
|
+
const version = buffer.readInt16LE();
|
|
12
|
+
let cyanvasVersion = buffer.readInt16LE();
|
|
13
|
+
if (version < 3) {
|
|
14
|
+
throw new Error('Unsupported MMWS version');
|
|
15
|
+
}
|
|
16
|
+
if (header === 'CCMMWS' && cyanvasVersion === 0) {
|
|
17
|
+
cyanvasVersion = 1;
|
|
18
|
+
}
|
|
19
|
+
const metadataPointer = buffer.readUInt32LE();
|
|
20
|
+
const eventsPointer = buffer.readUInt32LE();
|
|
21
|
+
const tapsPointer = buffer.readUInt32LE();
|
|
22
|
+
const holdsPointer = buffer.readUInt32LE();
|
|
23
|
+
const damagesPointer = cyanvasVersion > 0 ? buffer.readUInt32LE() : 0;
|
|
24
|
+
const layersPointer = cyanvasVersion >= 4 ? buffer.readUInt32LE() : 0;
|
|
25
|
+
// const waypointsPointer = cyanvasVersion >= 5 ? buffer.readUInt32LE() : 0
|
|
26
|
+
buffer.seek(metadataPointer);
|
|
27
|
+
const metadata = {
|
|
28
|
+
title: buffer.readString(),
|
|
29
|
+
author: buffer.readString(),
|
|
30
|
+
artist: buffer.readString(),
|
|
31
|
+
musicFile: buffer.readString(),
|
|
32
|
+
musicOffset: buffer.readFloat32LE(),
|
|
33
|
+
jacketFile: buffer.readString(),
|
|
34
|
+
};
|
|
35
|
+
buffer.seek(eventsPointer);
|
|
36
|
+
const events = {
|
|
37
|
+
timeSignatures: [],
|
|
38
|
+
bpmChanges: [],
|
|
39
|
+
hispeedChanges: [],
|
|
40
|
+
skills: [],
|
|
41
|
+
fever: {
|
|
42
|
+
start: 0,
|
|
43
|
+
end: 0,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const timeSignaturesCount = buffer.readInt32LE();
|
|
47
|
+
for (let i = 0; i < timeSignaturesCount; i++) {
|
|
48
|
+
events.timeSignatures.push({
|
|
49
|
+
measure: buffer.readInt32LE(),
|
|
50
|
+
numerator: buffer.readInt32LE(),
|
|
51
|
+
denominator: buffer.readInt32LE(),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const bpmChangesCount = buffer.readInt32LE();
|
|
55
|
+
for (let i = 0; i < bpmChangesCount; i++) {
|
|
56
|
+
events.bpmChanges.push({
|
|
57
|
+
tick: buffer.readInt32LE(),
|
|
58
|
+
bpm: buffer.readFloat32LE(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const hispeedChangesCount = buffer.readInt32LE();
|
|
62
|
+
for (let i = 0; i < hispeedChangesCount; i++) {
|
|
63
|
+
events.hispeedChanges.push({
|
|
64
|
+
tick: buffer.readInt32LE(),
|
|
65
|
+
speed: buffer.readFloat32LE(),
|
|
66
|
+
layer: cyanvasVersion >= 4 ? buffer.readInt32LE() : 0,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const skillsCount = buffer.readInt32LE();
|
|
70
|
+
for (let i = 0; i < skillsCount; i++) {
|
|
71
|
+
events.skills.push(buffer.readInt32LE());
|
|
72
|
+
}
|
|
73
|
+
events.fever.start = buffer.readInt32LE();
|
|
74
|
+
events.fever.end = buffer.readInt32LE();
|
|
75
|
+
buffer.seek(tapsPointer);
|
|
76
|
+
const taps = [];
|
|
77
|
+
const tapsCount = buffer.readInt32LE();
|
|
78
|
+
for (let i = 0; i < tapsCount; i++) {
|
|
79
|
+
const tick = buffer.readInt32LE();
|
|
80
|
+
const lane = buffer.readInt32LE();
|
|
81
|
+
const width = buffer.readInt32LE();
|
|
82
|
+
const layer = cyanvasVersion >= 4 ? buffer.readInt32LE() : 0;
|
|
83
|
+
const flickType = FlickType[buffer.readInt32LE()];
|
|
84
|
+
const flags = buffer.readInt32LE();
|
|
85
|
+
taps.push({
|
|
86
|
+
tick,
|
|
87
|
+
lane,
|
|
88
|
+
width,
|
|
89
|
+
flickType,
|
|
90
|
+
flags: {
|
|
91
|
+
critical: !!(flags & (1 << 0)),
|
|
92
|
+
friction: !!(flags & (1 << 1)),
|
|
93
|
+
},
|
|
94
|
+
layer,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
buffer.seek(holdsPointer);
|
|
98
|
+
const holds = [];
|
|
99
|
+
const holdsCount = buffer.readInt32LE();
|
|
100
|
+
for (let i = 0; i < holdsCount; i++) {
|
|
101
|
+
const holdFlags = version >= 4 ? buffer.readInt32LE() : 0;
|
|
102
|
+
const startTick = buffer.readInt32LE();
|
|
103
|
+
const startLane = buffer.readInt32LE();
|
|
104
|
+
const startWidth = buffer.readInt32LE();
|
|
105
|
+
const startLayer = cyanvasVersion >= 4 ? buffer.readInt32LE() : 0;
|
|
106
|
+
const startFlags = buffer.readInt32LE();
|
|
107
|
+
const startEase = EaseType[buffer.readInt32LE()];
|
|
108
|
+
const fadeType = cyanvasVersion >= 2 ? buffer.readInt32LE() : 0;
|
|
109
|
+
const guideColor = cyanvasVersion >= 3 ? buffer.readInt32LE() : startFlags & (1 << 0) ? 4 : 2;
|
|
110
|
+
const stepsCount = buffer.readInt32LE();
|
|
111
|
+
const steps = [];
|
|
112
|
+
for (let j = 0; j < stepsCount; j++) {
|
|
113
|
+
const tick = buffer.readInt32LE();
|
|
114
|
+
const lane = buffer.readInt32LE();
|
|
115
|
+
const width = buffer.readInt32LE();
|
|
116
|
+
const layer = cyanvasVersion >= 4 ? buffer.readInt32LE() : 0;
|
|
117
|
+
buffer.readInt32LE(); // unused flags
|
|
118
|
+
const type = StepType[buffer.readInt32LE()];
|
|
119
|
+
const ease = EaseType[buffer.readInt32LE()];
|
|
120
|
+
steps.push({
|
|
121
|
+
tick,
|
|
122
|
+
lane,
|
|
123
|
+
width,
|
|
124
|
+
type,
|
|
125
|
+
ease,
|
|
126
|
+
layer,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const endTick = buffer.readInt32LE();
|
|
130
|
+
const endLane = buffer.readInt32LE();
|
|
131
|
+
const endWidth = buffer.readInt32LE();
|
|
132
|
+
const endLayer = cyanvasVersion >= 4 ? buffer.readInt32LE() : 0;
|
|
133
|
+
const endFlickType = FlickType[buffer.readInt32LE()];
|
|
134
|
+
const endFlags = buffer.readInt32LE();
|
|
135
|
+
holds.push({
|
|
136
|
+
flags: {
|
|
137
|
+
startHidden: !!(holdFlags & (1 << 0)),
|
|
138
|
+
endHidden: !!(holdFlags & (1 << 1)),
|
|
139
|
+
guide: !!(holdFlags & (1 << 2)),
|
|
140
|
+
},
|
|
141
|
+
start: {
|
|
142
|
+
tick: startTick,
|
|
143
|
+
lane: startLane,
|
|
144
|
+
width: startWidth,
|
|
145
|
+
ease: startEase,
|
|
146
|
+
flags: {
|
|
147
|
+
critical: !!(startFlags & (1 << 0)),
|
|
148
|
+
friction: !!(startFlags & (1 << 1)),
|
|
149
|
+
},
|
|
150
|
+
layer: startLayer,
|
|
151
|
+
},
|
|
152
|
+
fadeType,
|
|
153
|
+
guideColor,
|
|
154
|
+
steps,
|
|
155
|
+
end: {
|
|
156
|
+
tick: endTick,
|
|
157
|
+
lane: endLane,
|
|
158
|
+
width: endWidth,
|
|
159
|
+
flags: {
|
|
160
|
+
critical: !!(endFlags & (1 << 0)),
|
|
161
|
+
friction: !!(endFlags & (1 << 1)),
|
|
162
|
+
},
|
|
163
|
+
flickType: endFlickType,
|
|
164
|
+
layer: endLayer,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
events.timeSignatures.sort((a, b) => a.measure - b.measure);
|
|
169
|
+
events.bpmChanges.sort((a, b) => a.tick - b.tick);
|
|
170
|
+
events.hispeedChanges.sort((a, b) => a.tick - b.tick);
|
|
171
|
+
events.skills.sort((a, b) => a - b);
|
|
172
|
+
taps.sort((a, b) => a.tick - b.tick);
|
|
173
|
+
holds.sort((a, b) => a.start.tick - b.start.tick);
|
|
174
|
+
const damages = [];
|
|
175
|
+
if (cyanvasVersion >= 1) {
|
|
176
|
+
buffer.seek(damagesPointer);
|
|
177
|
+
const damagesCount = buffer.readInt32LE();
|
|
178
|
+
for (let i = 0; i < damagesCount; i++) {
|
|
179
|
+
const tick = buffer.readInt32LE();
|
|
180
|
+
const lane = buffer.readInt32LE();
|
|
181
|
+
const width = buffer.readInt32LE();
|
|
182
|
+
const layer = cyanvasVersion >= 4 ? buffer.readInt32LE() : 0;
|
|
183
|
+
const flickType = FlickType[buffer.readInt32LE()];
|
|
184
|
+
const flags = buffer.readInt32LE();
|
|
185
|
+
damages.push({
|
|
186
|
+
tick,
|
|
187
|
+
lane,
|
|
188
|
+
width,
|
|
189
|
+
flickType,
|
|
190
|
+
layer,
|
|
191
|
+
flags: {
|
|
192
|
+
critical: !!(flags & (1 << 0)),
|
|
193
|
+
friction: !!(flags & (1 << 1)),
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
damages.sort((a, b) => a.tick - b.tick);
|
|
198
|
+
}
|
|
199
|
+
let numLayers = 1;
|
|
200
|
+
if (cyanvasVersion >= 4) {
|
|
201
|
+
buffer.seek(layersPointer);
|
|
202
|
+
numLayers = buffer.readInt32LE();
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
metadata,
|
|
206
|
+
events,
|
|
207
|
+
taps,
|
|
208
|
+
holds,
|
|
209
|
+
damages,
|
|
210
|
+
numLayers,
|
|
211
|
+
};
|
|
212
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { USCColor, } from '../usc/index.js';
|
|
2
|
+
import { analyze } from './analyze.js';
|
|
3
|
+
const mmwsEaseToUSCEase = {
|
|
4
|
+
linear: 'linear',
|
|
5
|
+
easeOut: 'out',
|
|
6
|
+
easeIn: 'in',
|
|
7
|
+
easeInOut: 'inout',
|
|
8
|
+
easeOutIn: 'outin',
|
|
9
|
+
};
|
|
10
|
+
const ticksPerBeat = 480;
|
|
11
|
+
const laneToUSCLane = ({ lane, width }) => {
|
|
12
|
+
return lane - 6 + width / 2;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Convert MMWS or CCMMWS to a USC
|
|
16
|
+
*/
|
|
17
|
+
export const mmwsToUSC = (mmws) => {
|
|
18
|
+
const score = analyze(mmws);
|
|
19
|
+
const usc = {
|
|
20
|
+
objects: [],
|
|
21
|
+
offset: score.metadata.musicOffset / -1000,
|
|
22
|
+
};
|
|
23
|
+
for (const bpmChange of score.events.bpmChanges) {
|
|
24
|
+
usc.objects.push({
|
|
25
|
+
type: 'bpm',
|
|
26
|
+
beat: bpmChange.tick / ticksPerBeat,
|
|
27
|
+
bpm: bpmChange.bpm,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const tsGroups = new Map();
|
|
31
|
+
for (let i = 0; i < score.numLayers; i++) {
|
|
32
|
+
tsGroups.set(i, []);
|
|
33
|
+
}
|
|
34
|
+
for (const hispeedChange of score.events.hispeedChanges) {
|
|
35
|
+
const key = hispeedChange.layer;
|
|
36
|
+
if (!tsGroups.has(key)) {
|
|
37
|
+
throw new Error('Invalid layer');
|
|
38
|
+
}
|
|
39
|
+
tsGroups.get(key).push({
|
|
40
|
+
beat: hispeedChange.tick / ticksPerBeat,
|
|
41
|
+
timeScale: hispeedChange.speed,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
for (const changes of tsGroups.values()) {
|
|
45
|
+
usc.objects.push({
|
|
46
|
+
type: 'timeScaleGroup',
|
|
47
|
+
changes,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (const tap of score.taps) {
|
|
51
|
+
const uscTap = {
|
|
52
|
+
type: 'single',
|
|
53
|
+
beat: tap.tick / ticksPerBeat,
|
|
54
|
+
timeScaleGroup: tap.layer,
|
|
55
|
+
critical: tap.flags.critical,
|
|
56
|
+
lane: laneToUSCLane(tap),
|
|
57
|
+
size: tap.width / 2,
|
|
58
|
+
trace: tap.flags.friction,
|
|
59
|
+
};
|
|
60
|
+
if (tap.flickType !== 'none') {
|
|
61
|
+
uscTap.direction = tap.flickType;
|
|
62
|
+
}
|
|
63
|
+
usc.objects.push(uscTap);
|
|
64
|
+
}
|
|
65
|
+
for (const hold of score.holds) {
|
|
66
|
+
const uscStartNote = {
|
|
67
|
+
type: 'start',
|
|
68
|
+
beat: hold.start.tick / ticksPerBeat,
|
|
69
|
+
timeScaleGroup: hold.start.layer,
|
|
70
|
+
critical: hold.start.flags.critical,
|
|
71
|
+
ease: mmwsEaseToUSCEase[hold.start.ease],
|
|
72
|
+
lane: laneToUSCLane(hold.start),
|
|
73
|
+
size: hold.start.width / 2,
|
|
74
|
+
judgeType: hold.flags.startHidden
|
|
75
|
+
? 'none'
|
|
76
|
+
: hold.start.flags.friction
|
|
77
|
+
? 'trace'
|
|
78
|
+
: 'normal',
|
|
79
|
+
};
|
|
80
|
+
const uscEndNote = {
|
|
81
|
+
type: 'end',
|
|
82
|
+
beat: hold.end.tick / ticksPerBeat,
|
|
83
|
+
timeScaleGroup: hold.end.layer,
|
|
84
|
+
critical: hold.end.flags.critical,
|
|
85
|
+
lane: laneToUSCLane(hold.end),
|
|
86
|
+
size: hold.end.width / 2,
|
|
87
|
+
judgeType: hold.flags.endHidden ? 'none' : hold.end.flags.friction ? 'trace' : 'normal',
|
|
88
|
+
};
|
|
89
|
+
if (hold.end.flickType !== 'none') {
|
|
90
|
+
uscEndNote.direction = hold.end.flickType;
|
|
91
|
+
}
|
|
92
|
+
if (hold.flags.guide) {
|
|
93
|
+
const uscGuide = {
|
|
94
|
+
type: 'guide',
|
|
95
|
+
fade: hold.fadeType === 0 ? 'out' : hold.fadeType === 1 ? 'none' : 'in',
|
|
96
|
+
color: Object.entries(USCColor).find(([, i]) => i === hold.guideColor)[0],
|
|
97
|
+
midpoints: [hold.start, ...hold.steps, hold.end].map((step) => ({
|
|
98
|
+
beat: step.tick / ticksPerBeat,
|
|
99
|
+
lane: laneToUSCLane(step),
|
|
100
|
+
size: step.width / 2,
|
|
101
|
+
timeScaleGroup: step.layer,
|
|
102
|
+
ease: 'ease' in step ? mmwsEaseToUSCEase[step.ease] : 'linear',
|
|
103
|
+
})),
|
|
104
|
+
};
|
|
105
|
+
usc.objects.push(uscGuide);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const uscSlide = {
|
|
109
|
+
type: 'slide',
|
|
110
|
+
critical: hold.start.flags.critical,
|
|
111
|
+
connections: [
|
|
112
|
+
uscStartNote,
|
|
113
|
+
...hold.steps.map((step) => {
|
|
114
|
+
const beat = step.tick / ticksPerBeat;
|
|
115
|
+
const lane = laneToUSCLane(step);
|
|
116
|
+
const size = step.width / 2;
|
|
117
|
+
if (step.type === 'ignored') {
|
|
118
|
+
return {
|
|
119
|
+
type: 'attach',
|
|
120
|
+
beat,
|
|
121
|
+
critical: hold.start.flags.critical,
|
|
122
|
+
timeScaleGroup: step.layer,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const uscStep = {
|
|
127
|
+
type: 'tick',
|
|
128
|
+
beat,
|
|
129
|
+
timeScaleGroup: step.layer,
|
|
130
|
+
lane,
|
|
131
|
+
size,
|
|
132
|
+
ease: mmwsEaseToUSCEase[step.ease],
|
|
133
|
+
};
|
|
134
|
+
if (step.type === 'visible') {
|
|
135
|
+
uscStep.critical = hold.start.flags.critical;
|
|
136
|
+
}
|
|
137
|
+
return uscStep;
|
|
138
|
+
}
|
|
139
|
+
}),
|
|
140
|
+
uscEndNote,
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
usc.objects.push(uscSlide);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (const damage of score.damages) {
|
|
147
|
+
const uscDamage = {
|
|
148
|
+
type: 'damage',
|
|
149
|
+
beat: damage.tick / ticksPerBeat,
|
|
150
|
+
timeScaleGroup: damage.layer,
|
|
151
|
+
lane: laneToUSCLane(damage),
|
|
152
|
+
size: damage.width / 2,
|
|
153
|
+
};
|
|
154
|
+
usc.objects.push(uscDamage);
|
|
155
|
+
}
|
|
156
|
+
return usc;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Convert CCMMWS to a USC
|
|
160
|
+
*/
|
|
161
|
+
export const ccmmwsToUSC = mmwsToUSC;
|
package/dist/usc/convert.js
CHANGED
|
@@ -357,8 +357,17 @@ export const uscToLevelData = (usc, offset = 0) => {
|
|
|
357
357
|
let prevMidpointIntermediate = null;
|
|
358
358
|
let headMidpointIntermediate = null;
|
|
359
359
|
const guideConnectors = [];
|
|
360
|
+
const stepSize = Math.max(1, connections.length - 1);
|
|
361
|
+
let stepIdx = 0;
|
|
360
362
|
for (const midpointNote of connections) {
|
|
361
363
|
const timeScaleGroupRef = timeScaleGroupIntermediates[midpointNote.timeScaleGroup ?? 0];
|
|
364
|
+
let segmentAlpha = 1;
|
|
365
|
+
if (guideNote.fade === 'out') {
|
|
366
|
+
segmentAlpha = 1 - 0.8 * (stepIdx / stepSize);
|
|
367
|
+
}
|
|
368
|
+
else if (guideNote.fade === 'in') {
|
|
369
|
+
segmentAlpha = 1 - 0.8 * ((stepSize - stepIdx) / stepSize);
|
|
370
|
+
}
|
|
362
371
|
const midpointIntermediate = createIntermediate('AnchorNote', {
|
|
363
372
|
'#BEAT': midpointNote.beat,
|
|
364
373
|
lane: midpointNote.lane,
|
|
@@ -366,9 +375,9 @@ export const uscToLevelData = (usc, offset = 0) => {
|
|
|
366
375
|
direction: SONOLUS_DIRECTIONS.up,
|
|
367
376
|
isAttached: 0,
|
|
368
377
|
connectorEase: SONOLUS_CONNECTOR_EASES[mapUscEaseToSonolusEase(midpointNote.ease)],
|
|
369
|
-
isSeparator:
|
|
378
|
+
isSeparator: 1,
|
|
370
379
|
segmentKind: SONOLUS_GUIDE_COLORS[guideNote.color],
|
|
371
|
-
segmentAlpha:
|
|
380
|
+
segmentAlpha: segmentAlpha,
|
|
372
381
|
'#TIMESCALE_GROUP': timeScaleGroupRef,
|
|
373
382
|
});
|
|
374
383
|
if (headMidpointIntermediate === null) {
|
|
@@ -383,6 +392,7 @@ export const uscToLevelData = (usc, offset = 0) => {
|
|
|
383
392
|
prevMidpointIntermediate.data['next'] = midpointIntermediate;
|
|
384
393
|
}
|
|
385
394
|
prevMidpointIntermediate = midpointIntermediate;
|
|
395
|
+
stepIdx++;
|
|
386
396
|
}
|
|
387
397
|
if (!headMidpointIntermediate || !prevMidpointIntermediate) {
|
|
388
398
|
continue;
|
|
@@ -393,16 +403,6 @@ export const uscToLevelData = (usc, offset = 0) => {
|
|
|
393
403
|
connectorIntermediate.data['activeHead'] = headMidpointIntermediate;
|
|
394
404
|
connectorIntermediate.data['activeTail'] = prevMidpointIntermediate;
|
|
395
405
|
}
|
|
396
|
-
switch (guideNote.fade) {
|
|
397
|
-
case 'in':
|
|
398
|
-
headMidpointIntermediate.data['segmentAlpha'] = 0;
|
|
399
|
-
break;
|
|
400
|
-
case 'out':
|
|
401
|
-
prevMidpointIntermediate.data['segmentAlpha'] = 0;
|
|
402
|
-
break;
|
|
403
|
-
case 'none':
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
406
|
}
|
|
407
407
|
simLineEligibleNotes.sort((noteA, noteB) => {
|
|
408
408
|
const beatA = noteA.data['#BEAT'];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonolus-next-rush-plus-engine",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4-kizuruki",
|
|
4
4
|
"description": "A new Project Sekai inspired engine for Sonolus",
|
|
5
5
|
"author": "Hyeon2",
|
|
6
6
|
"repository": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"build": "tsc -p . && node ./build.js"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@sevenc-nanashi/binaryseeker": "npm:@jsr/sevenc-nanashi__binaryseeker@^1.2.1",
|
|
36
37
|
"@sonolus/core": "~7.14.2"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|