sonolus-next-rush-engine 1.0.4 → 1.0.6

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.
@@ -87,6 +87,8 @@ const guideKindMapping = {
87
87
  6: ConnectorKind.GUIDE_CYAN,
88
88
  7: ConnectorKind.GUIDE_BLACK,
89
89
  };
90
+ const LEGACY_DEFAULT_NOTE_DURATION = 2;
91
+ const LEGACY_MIN_HIDDEN_POP_WINDOW = 1 / 30;
90
92
  class ExtData {
91
93
  constructor(entities) {
92
94
  this.byArch = new Map();
@@ -334,6 +336,28 @@ export const extendedToLevelData = (data, offset = 0) => {
334
336
  }
335
337
  return scaledTime;
336
338
  }
339
+ function createHideUntilTimescaleGroup(showBeat) {
340
+ const group = new EntityBuilder('#TIMESCALE_GROUP');
341
+ const hide = new EntityBuilder('#TIMESCALE_CHANGE');
342
+ const show = new EntityBuilder('#TIMESCALE_CHANGE');
343
+ const hideBeat = Math.min(0, showBeat - 1e-6);
344
+ hide.set('#BEAT', hideBeat);
345
+ hide.set('#TIMESCALE', 1);
346
+ hide.set('#TIMESCALE_SKIP', 0);
347
+ hide.set('#TIMESCALE_GROUP', group);
348
+ hide.set('#TIMESCALE_EASE', 0);
349
+ hide.set('hideNotes', 1);
350
+ hide.set('next', show);
351
+ show.set('#BEAT', showBeat);
352
+ show.set('#TIMESCALE', 1);
353
+ show.set('#TIMESCALE_SKIP', 0);
354
+ show.set('#TIMESCALE_GROUP', group);
355
+ show.set('#TIMESCALE_EASE', 0);
356
+ show.set('hideNotes', 0);
357
+ group.set('first', hide);
358
+ finalEntities.push(group, hide, show);
359
+ return group;
360
+ }
337
361
  const notesByIndex = new Map();
338
362
  const notesByName = new Map();
339
363
  const connectorsByIndex = new Map();
@@ -436,17 +460,32 @@ export const extendedToLevelData = (data, offset = 0) => {
436
460
  return createConnectorAnchor(beat, lerp(headLane, tailLane, easedFrac), lerp(headSize, tailSize, easedFrac), tsg, kind);
437
461
  });
438
462
  }
463
+ function isReverseHiddenPopConnector(headOriginal, tailOriginal) {
464
+ if (!headOriginal || !tailOriginal)
465
+ return false;
466
+ if (headOriginal.archetype !== 'HiddenSlideStartNote')
467
+ return false;
468
+ if (tailOriginal.archetype !== 'HiddenSlideTickNote')
469
+ return false;
470
+ return getNum(tailOriginal, '#BEAT') < getNum(headOriginal, '#BEAT') - 1e-6;
471
+ }
472
+ function getLegacyHiddenPopWindow(headOriginal, tailOriginal) {
473
+ const headTime = beatToTime(getNum(headOriginal, '#BEAT'));
474
+ const tailTime = beatToTime(getNum(tailOriginal, '#BEAT'));
475
+ return Math.max(LEGACY_MIN_HIDDEN_POP_WINDOW, LEGACY_DEFAULT_NOTE_DURATION - (headTime - tailTime));
476
+ }
439
477
  for (const { idx, e } of ext.connectors) {
440
478
  const startRef = getField(e, 'start');
441
479
  const headRef = getField(e, 'head');
442
480
  const tailRef = getField(e, 'tail');
443
481
  const rawHead = getNote(headRef);
444
482
  const tail = getNote(tailRef);
483
+ const rawHeadOriginal = resolveOriginal(ext, headRef);
484
+ const tailOriginal = resolveOriginal(ext, tailRef);
445
485
  const activeHead = getNote(startRef);
446
486
  const usesStartAsHead = shouldUseStartAsHead(startRef, headRef);
447
487
  const head = usesStartAsHead ? activeHead : rawHead;
448
488
  const headOriginal = resolveOriginal(ext, usesStartAsHead ? startRef : headRef);
449
- const tailOriginal = resolveOriginal(ext, tailRef);
450
489
  const endRef = getField(e, 'end');
451
490
  let activeTail = getNote(endRef);
452
491
  if (!activeTail) {
@@ -474,23 +513,41 @@ export const extendedToLevelData = (data, offset = 0) => {
474
513
  const kind = activeConnectorKindMapping[e.archetype];
475
514
  const ease = easeTypeMapping[getNum(e, 'ease')] ?? EaseType.LINEAR;
476
515
  const tsg = headOriginal ? getTSG(getField(headOriginal, 'timeScaleGroup')) : undefined;
477
- const splitAnchors = headOriginal && tailOriginal
516
+ const reverseHiddenPopConnector = isReverseHiddenPopConnector(rawHeadOriginal, tailOriginal);
517
+ const splitAnchors = headOriginal && tailOriginal && !reverseHiddenPopConnector
478
518
  ? getConnectorSplitAnchors(headOriginal, tailOriginal, tsg, kind, ease)
479
519
  : [];
480
520
  const segmentEase = splitAnchors.length > 0 ? EaseType.LINEAR : ease;
481
521
  const segmentNotes = [head, ...splitAnchors, tail];
482
- for (let i = 0; i < segmentNotes.length - 1; i++) {
483
- const segmentHead = segmentNotes[i];
484
- const segmentTail = segmentNotes[i + 1];
522
+ if (reverseHiddenPopConnector && rawHeadOriginal && tailOriginal) {
523
+ const popWindow = getLegacyHiddenPopWindow(rawHeadOriginal, tailOriginal);
524
+ const showTime = beatToTime(getNum(tailOriginal, '#BEAT')) - popWindow;
525
+ const showBeat = timeToBeat(showTime);
526
+ const gateTsg = createHideUntilTimescaleGroup(showBeat);
527
+ const segmentHead = createConnectorAnchor(getNum(rawHeadOriginal, '#BEAT'), getNum(rawHeadOriginal, 'lane'), getNum(rawHeadOriginal, 'size'), gateTsg, kind);
485
528
  const connector = new EntityBuilder('Connector');
486
- connector.set('head', segmentHead);
487
- connector.set('tail', segmentTail);
529
+ connector.set('head', head);
530
+ connector.set('tail', tail);
488
531
  connector.set('segmentHead', segmentHead);
489
- connector.set('segmentTail', segmentTail);
532
+ connector.set('segmentTail', tail);
490
533
  connector.set('activeHead', activeHead);
491
534
  connector.set('activeTail', activeTail);
492
535
  finalEntities.push(connector);
493
536
  }
537
+ else {
538
+ for (let i = 0; i < segmentNotes.length - 1; i++) {
539
+ const segmentHead = segmentNotes[i];
540
+ const segmentTail = segmentNotes[i + 1];
541
+ const connector = new EntityBuilder('Connector');
542
+ connector.set('head', segmentHead);
543
+ connector.set('tail', segmentTail);
544
+ connector.set('segmentHead', segmentHead);
545
+ connector.set('segmentTail', segmentTail);
546
+ connector.set('activeHead', activeHead);
547
+ connector.set('activeTail', activeTail);
548
+ finalEntities.push(connector);
549
+ }
550
+ }
494
551
  const connectorLink = new EntityBuilder('Connector');
495
552
  connectorLink.set('head', head);
496
553
  connectorLink.set('tail', tail);
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ import { USC } from './usc/index.js';
7
7
  export * from './usc/index.js';
8
8
  export { type ExtendedEntityData, type ExtendedEntityDataField, extendedToLevelData, mmwsToUSC, susToUSC, ucmmwsToLevelData, uscToLevelData, };
9
9
  export declare const convertToLevelData: (input: string | Uint8Array | USC | LevelData, offset?: number) => LevelData;
10
- export declare const version = "1.0.4";
10
+ export declare const version = "1.0.6";
11
11
  export declare const databaseEngineItem: {
12
12
  readonly name: "next-rush";
13
13
  readonly version: 13;
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ export const convertToLevelData = (input, offset = 0) => {
65
65
  }
66
66
  return uscToLevelData(usc, offset, true, true);
67
67
  };
68
- export const version = '1.0.4';
68
+ export const version = '1.0.6';
69
69
  export const databaseEngineItem = {
70
70
  name: 'next-rush',
71
71
  version: 13,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonolus-next-rush-engine",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Perspective-lane rhythm game for Sonolus",
5
5
  "author": "Hyeon2",
6
6
  "repository": {