sonolus-next-rush-plus-engine 1.5.7 → 1.5.8

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.
Binary file
@@ -82,6 +82,13 @@ const guideKindMapping = {
82
82
  6: ConnectorKind.GUIDE_CYAN,
83
83
  7: ConnectorKind.GUIDE_BLACK,
84
84
  };
85
+ const getNum = (data, key, defaultValue = 0) => {
86
+ const val = data[key];
87
+ if (val === undefined || val === null)
88
+ return defaultValue;
89
+ const n = Number(val);
90
+ return isNaN(n) ? defaultValue : n;
91
+ };
85
92
  /** Convert a PJSekaiExtendedLevelData to a Level Data (Next Sekai) */
86
93
  export const extendedToLevelData = (data, offset = 0) => {
87
94
  const allIntermediateEntities = [];
@@ -94,94 +101,94 @@ export const extendedToLevelData = (data, offset = 0) => {
94
101
  for (const entity of data.entities) {
95
102
  if (entity.archetype === '#BPM_CHANGE') {
96
103
  createIntermediate('#BPM_CHANGE', {
97
- '#BEAT': entity.data['#BEAT'],
98
- '#BPM': entity.data['#BPM'],
104
+ '#BEAT': getNum(entity.data, '#BEAT'),
105
+ '#BPM': getNum(entity.data, '#BPM'),
99
106
  });
100
107
  }
101
108
  }
102
109
  const timescaleGroupsByIndex = new Map();
103
110
  for (let i = 0; i < data.entities.length; i++) {
104
111
  const entity = data.entities[i];
105
- if (entity.archetype === 'TimeScaleGroup') {
106
- const groupIntermediate = createIntermediate('TimeScaleGroup', {});
107
- timescaleGroupsByIndex.set(i, groupIntermediate);
108
- let rawChangeIdx = entity.data['first'];
109
- let lastChangeIntermediate = null;
110
- while (rawChangeIdx !== undefined && rawChangeIdx > 0) {
111
- const rawChange = data.entities[rawChangeIdx];
112
- const changeIntermediate = createIntermediate('TimeScaleChange', {
113
- '#BEAT': rawChange.data['#BEAT'],
114
- timeScale: rawChange.data['timeScale'],
115
- timeScaleSkip: 0.0,
116
- timeScaleGroup: groupIntermediate,
117
- timeScaleEase: 0,
118
- });
119
- if (lastChangeIntermediate) {
120
- lastChangeIntermediate.data['next'] = changeIntermediate;
121
- }
122
- else {
123
- groupIntermediate.data['first'] = changeIntermediate;
124
- }
125
- lastChangeIntermediate = changeIntermediate;
126
- const nextIdx = rawChange.data['next'];
127
- if (nextIdx !== undefined && nextIdx > 0) {
128
- rawChangeIdx = nextIdx;
129
- }
130
- else {
131
- break;
132
- }
112
+ if (entity.archetype !== 'TimeScaleGroup')
113
+ continue;
114
+ const groupIntermediate = createIntermediate('TimeScaleGroup', {});
115
+ timescaleGroupsByIndex.set(i, groupIntermediate);
116
+ let rawChangeIdx = getNum(entity.data, 'first', -1);
117
+ if (rawChangeIdx < 0)
118
+ continue;
119
+ let lastChangeIntermediate = null;
120
+ while (true) {
121
+ const rawChange = data.entities[rawChangeIdx];
122
+ if (!rawChange)
123
+ break;
124
+ const changeIntermediate = createIntermediate('TimeScaleChange', {
125
+ '#BEAT': getNum(rawChange.data, '#BEAT'),
126
+ timeScale: getNum(rawChange.data, 'timeScale'),
127
+ timeScaleSkip: 0.0,
128
+ timeScaleGroup: groupIntermediate,
129
+ timeScaleEase: 0,
130
+ });
131
+ if (lastChangeIntermediate) {
132
+ lastChangeIntermediate.data['next'] = changeIntermediate;
133
133
  }
134
+ else {
135
+ groupIntermediate.data['first'] = changeIntermediate;
136
+ }
137
+ lastChangeIntermediate = changeIntermediate;
138
+ const nextIdx = getNum(rawChange.data, 'next', 0);
139
+ if (nextIdx <= 0)
140
+ break;
141
+ rawChangeIdx = nextIdx;
134
142
  }
135
143
  }
136
144
  const notesByOriginalIndex = new Map();
137
145
  for (let i = 0; i < data.entities.length; i++) {
138
146
  const entity = data.entities[i];
139
- if (noteTypeMapping[entity.archetype]) {
140
- const mappedArchetype = noteTypeMapping[entity.archetype];
141
- const directionData = entity.data['direction'] ?? 0;
142
- const noteIntermediate = createIntermediate(mappedArchetype, {
143
- '#BEAT': entity.data['#BEAT'],
144
- lane: entity.data['lane'] ?? 0.0,
145
- size: entity.data['size'] ?? 0.0,
146
- direction: flickDirectionMapping[directionData],
147
- segmentKind: ConnectorKind.ACTIVE_NORMAL,
148
- });
149
- notesByOriginalIndex.set(i, noteIntermediate);
150
- }
147
+ const mappedArchetype = noteTypeMapping[entity.archetype];
148
+ if (!mappedArchetype)
149
+ continue;
150
+ const noteIntermediate = createIntermediate(mappedArchetype, {
151
+ '#BEAT': getNum(entity.data, '#BEAT'),
152
+ lane: getNum(entity.data, 'lane', 0),
153
+ size: getNum(entity.data, 'size', 0),
154
+ direction: flickDirectionMapping[getNum(entity.data, 'direction', 0)],
155
+ segmentKind: ConnectorKind.ACTIVE_NORMAL,
156
+ });
157
+ notesByOriginalIndex.set(i, noteIntermediate);
151
158
  }
152
159
  const connectorsByOriginalIndex = new Map();
153
160
  for (let i = 0; i < data.entities.length; i++) {
154
161
  const entity = data.entities[i];
155
- if (activeConnectorKindMapping[entity.archetype]) {
156
- const connectorKind = activeConnectorKindMapping[entity.archetype];
157
- const head = notesByOriginalIndex.get(entity.data['head']);
158
- const tail = notesByOriginalIndex.get(entity.data['tail']);
159
- const segmentHead = notesByOriginalIndex.get(entity.data['start']);
160
- const segmentTail = notesByOriginalIndex.get(entity.data['end']);
161
- if (!head || !tail || !segmentHead || !segmentTail)
162
- continue;
163
- const connectorIntermediate = createIntermediate('Connector', {
164
- head,
165
- tail,
166
- segmentHead,
167
- segmentTail,
168
- activeHead: segmentHead,
169
- activeTail: segmentTail,
170
- });
171
- head.data['connectorEase'] = easeTypeMapping[entity.data['ease'] ?? 0];
172
- head.data['segmentKind'] = connectorKind;
173
- tail.data['segmentKind'] = connectorKind;
174
- segmentHead.data['segmentKind'] = connectorKind;
175
- connectorsByOriginalIndex.set(i, connectorIntermediate);
176
- }
162
+ const connectorKind = activeConnectorKindMapping[entity.archetype];
163
+ if (!connectorKind)
164
+ continue;
165
+ const head = notesByOriginalIndex.get(getNum(entity.data, 'head'));
166
+ const tail = notesByOriginalIndex.get(getNum(entity.data, 'tail'));
167
+ const segmentHead = notesByOriginalIndex.get(getNum(entity.data, 'start'));
168
+ const segmentTail = notesByOriginalIndex.get(getNum(entity.data, 'end'));
169
+ if (!head || !tail || !segmentHead || !segmentTail)
170
+ continue;
171
+ const connectorIntermediate = createIntermediate('Connector', {
172
+ head,
173
+ tail,
174
+ segmentHead,
175
+ segmentTail,
176
+ activeHead: segmentHead,
177
+ activeTail: segmentTail,
178
+ });
179
+ head.data['connectorEase'] = easeTypeMapping[getNum(entity.data, 'ease', 0)];
180
+ head.data['segmentKind'] = connectorKind;
181
+ tail.data['segmentKind'] = connectorKind;
182
+ segmentHead.data['segmentKind'] = connectorKind;
183
+ connectorsByOriginalIndex.set(i, connectorIntermediate);
177
184
  }
178
185
  for (const [i, note] of notesByOriginalIndex.entries()) {
179
186
  const entity = data.entities[i];
180
- const timescaleGroupIndex = entity.data['timeScaleGroup'] ?? -1;
187
+ const timescaleGroupIndex = getNum(entity.data, 'timeScaleGroup', -1);
181
188
  if (timescaleGroupIndex >= 0 && timescaleGroupsByIndex.has(timescaleGroupIndex)) {
182
189
  note.data['#TIMESCALE_GROUP'] = timescaleGroupsByIndex.get(timescaleGroupIndex);
183
190
  }
184
- const attachIndex = entity.data['attach'] ?? -1;
191
+ const attachIndex = getNum(entity.data, 'attach', -1);
185
192
  if (attachIndex > 0) {
186
193
  const attachConnector = connectorsByOriginalIndex.get(attachIndex);
187
194
  if (attachConnector) {
@@ -190,7 +197,7 @@ export const extendedToLevelData = (data, offset = 0) => {
190
197
  note.data['isAttached'] = 1;
191
198
  }
192
199
  }
193
- const slideIndex = entity.data['slide'] ?? -1;
200
+ const slideIndex = getNum(entity.data, 'slide', -1);
194
201
  if (slideIndex > 0) {
195
202
  const slideConnector = connectorsByOriginalIndex.get(slideIndex);
196
203
  if (slideConnector) {
@@ -200,18 +207,18 @@ export const extendedToLevelData = (data, offset = 0) => {
200
207
  }
201
208
  for (let i = 0; i < data.entities.length; i++) {
202
209
  const entity = data.entities[i];
203
- if (entity.archetype === 'SimLine') {
204
- const left = notesByOriginalIndex.get(entity.data['a']);
205
- const right = notesByOriginalIndex.get(entity.data['b']);
206
- if (left && right) {
207
- createIntermediate('SimLine', { left, right });
208
- }
210
+ if (entity.archetype !== 'SimLine')
211
+ continue;
212
+ const left = notesByOriginalIndex.get(getNum(entity.data, 'a'));
213
+ const right = notesByOriginalIndex.get(getNum(entity.data, 'b'));
214
+ if (left && right) {
215
+ createIntermediate('SimLine', { left, right });
209
216
  }
210
217
  }
211
218
  const anchorsByBeat = new Map();
212
219
  const anchorPositions = new Map();
213
220
  const getAnchor = (beat, lane, size, timescaleGroup, pos, segmentKind = -1, segmentAlpha = -1, connectorEase = -1) => {
214
- let anchors = anchorsByBeat.get(beat);
221
+ const anchors = anchorsByBeat.get(beat);
215
222
  if (anchors) {
216
223
  for (const anchor of anchors) {
217
224
  if (anchorPositions.get(anchor)?.has(pos))
@@ -228,15 +235,12 @@ export const extendedToLevelData = (data, offset = 0) => {
228
235
  (connectorEase === -1 ||
229
236
  anchor.data['connectorEase'] === connectorEase ||
230
237
  anchor.data['connectorEase'] === -1)) {
231
- if (segmentKind !== -1 && anchor.data['segmentKind'] === -1) {
238
+ if (segmentKind !== -1 && anchor.data['segmentKind'] === -1)
232
239
  anchor.data['segmentKind'] = segmentKind;
233
- }
234
- if (segmentAlpha !== -1 && anchor.data['segmentAlpha'] === -1) {
240
+ if (segmentAlpha !== -1 && anchor.data['segmentAlpha'] === -1)
235
241
  anchor.data['segmentAlpha'] = segmentAlpha;
236
- }
237
- if (connectorEase !== -1 && anchor.data['connectorEase'] === -1) {
242
+ if (connectorEase !== -1 && anchor.data['connectorEase'] === -1)
238
243
  anchor.data['connectorEase'] = connectorEase;
239
- }
240
244
  anchorPositions.get(anchor).add(pos);
241
245
  return anchor;
242
246
  }
@@ -246,73 +250,63 @@ export const extendedToLevelData = (data, offset = 0) => {
246
250
  '#BEAT': beat,
247
251
  lane,
248
252
  size,
249
- '#TIMESCALE_GROUP': timescaleGroup,
253
+ ...(timescaleGroup !== undefined ? { '#TIMESCALE_GROUP': timescaleGroup } : {}),
250
254
  segmentKind,
251
255
  segmentAlpha,
252
256
  connectorEase,
253
257
  });
254
- if (!anchorsByBeat.has(beat)) {
258
+ if (!anchorsByBeat.has(beat))
255
259
  anchorsByBeat.set(beat, []);
256
- }
257
260
  anchorsByBeat.get(beat).push(anchor);
258
261
  anchorPositions.set(anchor, new Set([pos]));
259
262
  return anchor;
260
263
  };
261
264
  for (let i = 0; i < data.entities.length; i++) {
262
265
  const entity = data.entities[i];
263
- if (entity.archetype === 'Guide') {
264
- const startBeat = entity.data['startBeat'];
265
- const startLane = entity.data['startLane'];
266
- const startSize = entity.data['startSize'];
267
- const startTimeScaleGroup = timescaleGroupsByIndex.get(entity.data['startTimeScaleGroup']);
268
- const headBeat = entity.data['headBeat'];
269
- const headLane = entity.data['headLane'];
270
- const headSize = entity.data['headSize'];
271
- const headTimeScaleGroup = timescaleGroupsByIndex.get(entity.data['headTimeScaleGroup']);
272
- const tailBeat = entity.data['tailBeat'];
273
- const tailLane = entity.data['tailLane'];
274
- const tailSize = entity.data['tailSize'];
275
- const tailTimeScaleGroup = timescaleGroupsByIndex.get(entity.data['tailTimeScaleGroup']);
276
- const endBeat = entity.data['endBeat'];
277
- const endLane = entity.data['endLane'];
278
- const endSize = entity.data['endSize'];
279
- const endTimeScaleGroup = timescaleGroupsByIndex.get(entity.data['endTimeScaleGroup']);
280
- const ease = easeTypeMapping[entity.data['ease'] ?? 0];
281
- const fade = entity.data['fade'] ?? 1;
282
- const [startAlpha, endAlpha] = fadeAlphaMapping[fade];
283
- const kind = guideKindMapping[entity.data['color'] ?? 0];
284
- const start = getAnchor(startBeat, startLane, startSize, startTimeScaleGroup, 'segmentHead', kind, startAlpha);
285
- const end = getAnchor(endBeat, endLane, endSize, endTimeScaleGroup, 'segmentTail', kind, endAlpha);
286
- const head = getAnchor(headBeat, headLane, headSize, headTimeScaleGroup, 'head', kind, -1, ease);
287
- const tail = getAnchor(tailBeat, tailLane, tailSize, tailTimeScaleGroup, 'tail', kind);
288
- createIntermediate('Connector', {
289
- head,
290
- tail,
291
- segmentHead: start,
292
- segmentTail: end,
293
- });
294
- }
266
+ if (entity.archetype !== 'Guide')
267
+ continue;
268
+ const startBeat = getNum(entity.data, 'startBeat');
269
+ const startLane = getNum(entity.data, 'startLane');
270
+ const startSize = getNum(entity.data, 'startSize');
271
+ const startTimeScaleGroup = timescaleGroupsByIndex.get(getNum(entity.data, 'startTimeScaleGroup'));
272
+ const headBeat = getNum(entity.data, 'headBeat');
273
+ const headLane = getNum(entity.data, 'headLane');
274
+ const headSize = getNum(entity.data, 'headSize');
275
+ const headTimeScaleGroup = timescaleGroupsByIndex.get(getNum(entity.data, 'headTimeScaleGroup'));
276
+ const tailBeat = getNum(entity.data, 'tailBeat');
277
+ const tailLane = getNum(entity.data, 'tailLane');
278
+ const tailSize = getNum(entity.data, 'tailSize');
279
+ const tailTimeScaleGroup = timescaleGroupsByIndex.get(getNum(entity.data, 'tailTimeScaleGroup'));
280
+ const endBeat = getNum(entity.data, 'endBeat');
281
+ const endLane = getNum(entity.data, 'endLane');
282
+ const endSize = getNum(entity.data, 'endSize');
283
+ const endTimeScaleGroup = timescaleGroupsByIndex.get(getNum(entity.data, 'endTimeScaleGroup'));
284
+ const ease = easeTypeMapping[getNum(entity.data, 'ease', 0)];
285
+ const [startAlpha, endAlpha] = fadeAlphaMapping[getNum(entity.data, 'fade', 1)];
286
+ const kind = guideKindMapping[getNum(entity.data, 'color', 0)];
287
+ const start = getAnchor(startBeat, startLane, startSize, startTimeScaleGroup, 'segmentHead', kind, startAlpha);
288
+ const end = getAnchor(endBeat, endLane, endSize, endTimeScaleGroup, 'segmentTail', kind, endAlpha);
289
+ const head = getAnchor(headBeat, headLane, headSize, headTimeScaleGroup, 'head', kind, -1, ease);
290
+ const tail = getAnchor(tailBeat, tailLane, tailSize, tailTimeScaleGroup, 'tail', kind);
291
+ createIntermediate('Connector', { head, tail, segmentHead: start, segmentTail: end });
295
292
  }
296
293
  for (const anchorList of anchorsByBeat.values()) {
297
294
  for (const anchor of anchorList) {
298
- if (anchor.data['segmentKind'] === -1) {
295
+ if (anchor.data['segmentKind'] === -1)
299
296
  anchor.data['segmentKind'] = ConnectorKind.GUIDE_NEUTRAL;
300
- }
301
- if (anchor.data['segmentAlpha'] === -1) {
297
+ if (anchor.data['segmentAlpha'] === -1)
302
298
  anchor.data['segmentAlpha'] = 1.0;
303
- }
304
- if (anchor.data['connectorEase'] === -1) {
299
+ if (anchor.data['connectorEase'] === -1)
305
300
  anchor.data['connectorEase'] = EaseType.LINEAR;
306
- }
307
301
  }
308
302
  }
309
303
  for (const entity of allIntermediateEntities) {
310
- if (entity.archetype === 'Connector') {
311
- const head = entity.data['head'];
312
- const tail = entity.data['tail'];
313
- if (head && tail) {
314
- head.data['next'] = tail;
315
- }
304
+ if (entity.archetype !== 'Connector')
305
+ continue;
306
+ const head = entity.data['head'];
307
+ const tail = entity.data['tail'];
308
+ if (head && tail) {
309
+ head.data['next'] = tail;
316
310
  }
317
311
  }
318
312
  allIntermediateEntities.sort((a, b) => {
@@ -329,7 +323,7 @@ export const extendedToLevelData = (data, offset = 0) => {
329
323
  let entityRefCounter = 0;
330
324
  const getRef = (intermediateEntity) => {
331
325
  let ref = intermediateToRef.get(intermediateEntity);
332
- if (ref)
326
+ if (ref !== undefined)
333
327
  return ref;
334
328
  ref = (entityRefCounter++).toString(16);
335
329
  intermediateToRef.set(intermediateEntity, ref);
@@ -345,6 +339,12 @@ export const extendedToLevelData = (data, offset = 0) => {
345
339
  if (typeof dataValue === 'number') {
346
340
  entity.data.push({ name: dataName, value: dataValue });
347
341
  }
342
+ else if (typeof dataValue === 'string') {
343
+ const asNum = Number(dataValue);
344
+ if (!isNaN(asNum)) {
345
+ entity.data.push({ name: dataName, value: asNum });
346
+ }
347
+ }
348
348
  else if (dataValue !== undefined && dataValue !== null) {
349
349
  entity.data.push({ name: dataName, ref: getRef(dataValue) });
350
350
  }
package/dist/index.d.ts CHANGED
@@ -4,11 +4,11 @@ import { ucmmwsToLevelData } from './mmw/convert.js';
4
4
  import { susToUSC } from './sus/convert.js';
5
5
  import { uscToLevelData } from './usc/convert.js';
6
6
  import { USC } from './usc/index.js';
7
- import { extendedToLevelData } from './extended/convert.js';
8
- export { susToUSC, mmwsToUSC, uscToLevelData, ucmmwsToLevelData, extendedToLevelData };
7
+ import { extendedToLevelData, type ExtendedEntityData, type ExtendedLevelData } from './extended/convert.js';
8
+ export { susToUSC, mmwsToUSC, uscToLevelData, ucmmwsToLevelData, extendedToLevelData, type ExtendedEntityData, type ExtendedLevelData, };
9
9
  export * from './usc/index.js';
10
10
  export declare const convertToLevelData: (input: string | Uint8Array | USC | LevelData, offset?: number) => LevelData;
11
- export declare const version = "1.5.7";
11
+ export declare const version = "1.5.8";
12
12
  export declare const databaseEngineItem: {
13
13
  readonly name: "next-rush-plus";
14
14
  readonly version: 13;
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@ import { isUSC } from './usc/analyze.js';
7
7
  import { isLevelData } from './LevelData/analyze.js';
8
8
  import { isPJSK } from './pjsk/analyze.js';
9
9
  import { pjskToUSC } from './pjsk/convert.js';
10
- import { extendedToLevelData } from './extended/convert.js';
11
- export { susToUSC, mmwsToUSC, uscToLevelData, ucmmwsToLevelData, extendedToLevelData };
10
+ import { extendedToLevelData, } from './extended/convert.js';
11
+ export { susToUSC, mmwsToUSC, uscToLevelData, ucmmwsToLevelData, extendedToLevelData, };
12
12
  export * from './usc/index.js';
13
13
  export const convertToLevelData = (input, offset = 0) => {
14
14
  if (isLevelData(input)) {
@@ -60,7 +60,7 @@ export const convertToLevelData = (input, offset = 0) => {
60
60
  }
61
61
  return uscToLevelData(usc, offset, true, true);
62
62
  };
63
- export const version = '1.5.7';
63
+ export const version = '1.5.8';
64
64
  export const databaseEngineItem = {
65
65
  name: 'next-rush-plus',
66
66
  version: 13,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonolus-next-rush-plus-engine",
3
- "version": "1.5.7",
3
+ "version": "1.5.8",
4
4
  "description": "A new Project Sekai inspired engine for Sonolus",
5
5
  "author": "Hyeon2",
6
6
  "repository": {