sonolus-next-rush-engine 1.0.4 → 1.0.5

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,7 @@ const guideKindMapping = {
87
87
  6: ConnectorKind.GUIDE_CYAN,
88
88
  7: ConnectorKind.GUIDE_BLACK,
89
89
  };
90
+ const LEGACY_HIDDEN_POP_WINDOW = 1 / 30;
90
91
  class ExtData {
91
92
  constructor(entities) {
92
93
  this.byArch = new Map();
@@ -334,6 +335,28 @@ export const extendedToLevelData = (data, offset = 0) => {
334
335
  }
335
336
  return scaledTime;
336
337
  }
338
+ function createHideUntilTimescaleGroup(showBeat) {
339
+ const group = new EntityBuilder('#TIMESCALE_GROUP');
340
+ const hide = new EntityBuilder('#TIMESCALE_CHANGE');
341
+ const show = new EntityBuilder('#TIMESCALE_CHANGE');
342
+ const hideBeat = Math.min(0, showBeat - 1e-6);
343
+ hide.set('#BEAT', hideBeat);
344
+ hide.set('#TIMESCALE', 1);
345
+ hide.set('#TIMESCALE_SKIP', 0);
346
+ hide.set('#TIMESCALE_GROUP', group);
347
+ hide.set('#TIMESCALE_EASE', 0);
348
+ hide.set('hideNotes', 1);
349
+ hide.set('next', show);
350
+ show.set('#BEAT', showBeat);
351
+ show.set('#TIMESCALE', 1);
352
+ show.set('#TIMESCALE_SKIP', 0);
353
+ show.set('#TIMESCALE_GROUP', group);
354
+ show.set('#TIMESCALE_EASE', 0);
355
+ show.set('hideNotes', 0);
356
+ group.set('first', hide);
357
+ finalEntities.push(group, hide, show);
358
+ return group;
359
+ }
337
360
  const notesByIndex = new Map();
338
361
  const notesByName = new Map();
339
362
  const connectorsByIndex = new Map();
@@ -436,17 +459,27 @@ export const extendedToLevelData = (data, offset = 0) => {
436
459
  return createConnectorAnchor(beat, lerp(headLane, tailLane, easedFrac), lerp(headSize, tailSize, easedFrac), tsg, kind);
437
460
  });
438
461
  }
462
+ function isReverseHiddenPopConnector(headOriginal, tailOriginal) {
463
+ if (!headOriginal || !tailOriginal)
464
+ return false;
465
+ if (headOriginal.archetype !== 'HiddenSlideStartNote')
466
+ return false;
467
+ if (tailOriginal.archetype !== 'HiddenSlideTickNote')
468
+ return false;
469
+ return getNum(tailOriginal, '#BEAT') < getNum(headOriginal, '#BEAT') - 1e-6;
470
+ }
439
471
  for (const { idx, e } of ext.connectors) {
440
472
  const startRef = getField(e, 'start');
441
473
  const headRef = getField(e, 'head');
442
474
  const tailRef = getField(e, 'tail');
443
475
  const rawHead = getNote(headRef);
444
476
  const tail = getNote(tailRef);
477
+ const rawHeadOriginal = resolveOriginal(ext, headRef);
478
+ const tailOriginal = resolveOriginal(ext, tailRef);
445
479
  const activeHead = getNote(startRef);
446
480
  const usesStartAsHead = shouldUseStartAsHead(startRef, headRef);
447
481
  const head = usesStartAsHead ? activeHead : rawHead;
448
482
  const headOriginal = resolveOriginal(ext, usesStartAsHead ? startRef : headRef);
449
- const tailOriginal = resolveOriginal(ext, tailRef);
450
483
  const endRef = getField(e, 'end');
451
484
  let activeTail = getNote(endRef);
452
485
  if (!activeTail) {
@@ -474,23 +507,40 @@ export const extendedToLevelData = (data, offset = 0) => {
474
507
  const kind = activeConnectorKindMapping[e.archetype];
475
508
  const ease = easeTypeMapping[getNum(e, 'ease')] ?? EaseType.LINEAR;
476
509
  const tsg = headOriginal ? getTSG(getField(headOriginal, 'timeScaleGroup')) : undefined;
477
- const splitAnchors = headOriginal && tailOriginal
510
+ const reverseHiddenPopConnector = isReverseHiddenPopConnector(rawHeadOriginal, tailOriginal);
511
+ const splitAnchors = headOriginal && tailOriginal && !reverseHiddenPopConnector
478
512
  ? getConnectorSplitAnchors(headOriginal, tailOriginal, tsg, kind, ease)
479
513
  : [];
480
514
  const segmentEase = splitAnchors.length > 0 ? EaseType.LINEAR : ease;
481
515
  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];
516
+ if (reverseHiddenPopConnector && rawHeadOriginal && tailOriginal) {
517
+ const showTime = beatToTime(getNum(tailOriginal, '#BEAT')) - LEGACY_HIDDEN_POP_WINDOW;
518
+ const showBeat = timeToBeat(showTime);
519
+ const gateTsg = createHideUntilTimescaleGroup(showBeat);
520
+ const segmentHead = createConnectorAnchor(getNum(rawHeadOriginal, '#BEAT'), getNum(rawHeadOriginal, 'lane'), getNum(rawHeadOriginal, 'size'), gateTsg, kind);
485
521
  const connector = new EntityBuilder('Connector');
486
- connector.set('head', segmentHead);
487
- connector.set('tail', segmentTail);
522
+ connector.set('head', head);
523
+ connector.set('tail', tail);
488
524
  connector.set('segmentHead', segmentHead);
489
- connector.set('segmentTail', segmentTail);
525
+ connector.set('segmentTail', tail);
490
526
  connector.set('activeHead', activeHead);
491
527
  connector.set('activeTail', activeTail);
492
528
  finalEntities.push(connector);
493
529
  }
530
+ else {
531
+ for (let i = 0; i < segmentNotes.length - 1; i++) {
532
+ const segmentHead = segmentNotes[i];
533
+ const segmentTail = segmentNotes[i + 1];
534
+ const connector = new EntityBuilder('Connector');
535
+ connector.set('head', segmentHead);
536
+ connector.set('tail', segmentTail);
537
+ connector.set('segmentHead', segmentHead);
538
+ connector.set('segmentTail', segmentTail);
539
+ connector.set('activeHead', activeHead);
540
+ connector.set('activeTail', activeTail);
541
+ finalEntities.push(connector);
542
+ }
543
+ }
494
544
  const connectorLink = new EntityBuilder('Connector');
495
545
  connectorLink.set('head', head);
496
546
  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.5";
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.5';
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.5",
4
4
  "description": "Perspective-lane rhythm game for Sonolus",
5
5
  "author": "Hyeon2",
6
6
  "repository": {