sonolus-next-rush-engine 1.0.16 → 1.0.18

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
@@ -60,6 +60,13 @@ const activeConnectorKindMapping = {
60
60
  NormalSlideConnector: ConnectorKind.ACTIVE_NORMAL,
61
61
  CriticalSlideConnector: ConnectorKind.ACTIVE_CRITICAL,
62
62
  };
63
+ const activeSlideStartArchetypes = new Set([
64
+ 'NormalSlideStartNote',
65
+ 'CriticalSlideStartNote',
66
+ 'HiddenSlideStartNote',
67
+ 'NormalTraceSlideStartNote',
68
+ 'CriticalTraceSlideStartNote',
69
+ ]);
63
70
  const flickDirectionMapping = {
64
71
  [-1]: FlickDirection.UP_LEFT,
65
72
  0: FlickDirection.UP_OMNI,
@@ -378,7 +385,7 @@ export const extendedToLevelData = (data, offset = 0) => {
378
385
  return false;
379
386
  if (head.archetype !== 'HiddenSlideStartNote')
380
387
  return false;
381
- if (!['NormalSlideStartNote', 'CriticalSlideStartNote'].includes(start.archetype))
388
+ if (!activeSlideStartArchetypes.has(start.archetype))
382
389
  return false;
383
390
  return (nearlyEqual(getNum(start, '#BEAT'), getNum(head, '#BEAT')) &&
384
391
  nearlyEqual(getNum(start, 'lane'), getNum(head, 'lane')) &&
@@ -457,7 +464,17 @@ export const extendedToLevelData = (data, offset = 0) => {
457
464
  return false;
458
465
  return getNum(tailOriginal, '#BEAT') < getNum(headOriginal, '#BEAT') - 1e-6;
459
466
  }
460
- function getUltimateTailRef(startRef, tailRef) {
467
+ function isSlideTickRef(ref) {
468
+ return [
469
+ 'IgnoredSlideTickNote',
470
+ 'NormalSlideTickNote',
471
+ 'CriticalSlideTickNote',
472
+ 'HiddenSlideTickNote',
473
+ 'NormalAttachedSlideTickNote',
474
+ 'CriticalAttachedSlideTickNote',
475
+ ].includes(resolveOriginal(ext, ref)?.archetype ?? '');
476
+ }
477
+ function getUltimateTailRef(archetype, startRef, tailRef) {
461
478
  let ultimateTailRef = tailRef;
462
479
  let ultimateTailBeat = getNum(resolveOriginal(ext, tailRef) ?? { archetype: '', data: [] }, '#BEAT');
463
480
  const visited = new Set();
@@ -466,7 +483,12 @@ export const extendedToLevelData = (data, offset = 0) => {
466
483
  if (headRef === undefined || visited.has(key))
467
484
  return;
468
485
  visited.add(key);
469
- const nextConnectors = ext.connectors.filter((c) => getField(c.e, 'head') === headRef && getField(c.e, 'start') === startRef);
486
+ const nextConnectors = ext.connectors.filter((c) => c.e.archetype === archetype &&
487
+ getField(c.e, 'head') === headRef &&
488
+ getField(c.e, 'start') === startRef);
489
+ if (nextConnectors.length === 0) {
490
+ nextConnectors.push(...ext.connectors.filter((c) => c.e.archetype === archetype && getField(c.e, 'head') === headRef));
491
+ }
470
492
  if (nextConnectors.length === 0) {
471
493
  const beat = getNum(resolveOriginal(ext, headRef) ?? { archetype: '', data: [] }, '#BEAT');
472
494
  if (beat >= ultimateTailBeat) {
@@ -482,29 +504,89 @@ export const extendedToLevelData = (data, offset = 0) => {
482
504
  visit(tailRef);
483
505
  return ultimateTailRef;
484
506
  }
507
+ function getUltimateStartRef(archetype, startRef, headRef) {
508
+ if (!isSlideTickRef(headRef))
509
+ return startRef;
510
+ let ultimateStartRef = startRef;
511
+ let ultimateStartBeat = getNum(resolveOriginal(ext, startRef) ?? { archetype: '', data: [] }, '#BEAT');
512
+ const visited = new Set();
513
+ function visit(currentHeadRef) {
514
+ const key = `${archetype}|${String(currentHeadRef)}`;
515
+ if (currentHeadRef === undefined || visited.has(key))
516
+ return;
517
+ visited.add(key);
518
+ if (!isSlideTickRef(currentHeadRef))
519
+ return;
520
+ const previousConnectors = ext.connectors.filter((c) => c.e.archetype === archetype && getField(c.e, 'tail') === currentHeadRef);
521
+ for (const previousConnector of previousConnectors) {
522
+ const previousStartRef = getField(previousConnector.e, 'start');
523
+ const previousStartBeat = getNum(resolveOriginal(ext, previousStartRef) ?? { archetype: '', data: [] }, '#BEAT');
524
+ if (previousStartBeat <= ultimateStartBeat) {
525
+ ultimateStartBeat = previousStartBeat;
526
+ ultimateStartRef = previousStartRef;
527
+ }
528
+ visit(getField(previousConnector.e, 'head'));
529
+ }
530
+ }
531
+ visit(headRef);
532
+ return ultimateStartRef;
533
+ }
485
534
  function setInferredActiveHead(note, activeHead) {
486
- if (note === activeHead)
487
- return;
488
535
  if (note.refs.activeHead)
489
536
  return;
490
537
  note.set('activeHead', activeHead);
491
538
  }
539
+ function isIgnoredSlideTickRef(ref) {
540
+ return resolveOriginal(ext, ref)?.archetype === 'IgnoredSlideTickNote';
541
+ }
542
+ function getNextConnectorWithHead(archetype, startRef, headRef) {
543
+ return (ext.connectors.find(({ e }) => e.archetype === archetype &&
544
+ getField(e, 'start') === startRef &&
545
+ getField(e, 'head') === headRef) ??
546
+ ext.connectors.find(({ e }) => e.archetype === archetype && getField(e, 'head') === headRef));
547
+ }
548
+ function resolveConnectorTailRef(archetype, startRef, tailRef) {
549
+ const skippedNoteRefs = [];
550
+ const skippedConnectors = [];
551
+ const visited = new Set();
552
+ let resolvedTailRef = tailRef;
553
+ while (isIgnoredSlideTickRef(resolvedTailRef)) {
554
+ if (resolvedTailRef === undefined)
555
+ break;
556
+ const key = String(resolvedTailRef);
557
+ if (visited.has(key))
558
+ break;
559
+ visited.add(key);
560
+ skippedNoteRefs.push(resolvedTailRef);
561
+ const nextConnector = getNextConnectorWithHead(archetype, startRef, resolvedTailRef);
562
+ if (!nextConnector)
563
+ break;
564
+ skippedConnectors.push(nextConnector);
565
+ resolvedTailRef = getField(nextConnector.e, 'tail');
566
+ }
567
+ return { tailRef: resolvedTailRef, skippedNoteRefs, skippedConnectors };
568
+ }
492
569
  for (const { idx, e } of ext.connectors) {
493
570
  const startRef = getField(e, 'start');
494
571
  const headRef = getField(e, 'head');
495
- const tailRef = getField(e, 'tail');
572
+ if (isIgnoredSlideTickRef(headRef))
573
+ continue;
574
+ const { tailRef, skippedNoteRefs, skippedConnectors } = resolveConnectorTailRef(e.archetype, startRef, getField(e, 'tail'));
575
+ if (isIgnoredSlideTickRef(tailRef))
576
+ continue;
496
577
  const tail = getNote(tailRef);
497
578
  const rawHeadOriginal = resolveOriginal(ext, headRef);
498
579
  const tailOriginal = resolveOriginal(ext, tailRef);
499
580
  const rawHead = getNote(headRef);
500
- const activeHead = getNote(startRef);
581
+ const activeStartRef = getUltimateStartRef(e.archetype, startRef, headRef);
582
+ const activeHead = getNote(activeStartRef);
501
583
  const usesStartAsHead = shouldUseStartAsHead(startRef, headRef);
502
584
  const head = usesStartAsHead ? activeHead : rawHead;
503
585
  const headOriginal = resolveOriginal(ext, usesStartAsHead ? startRef : headRef);
504
586
  const endRef = getField(e, 'end');
505
587
  let activeTail = getNote(endRef);
506
588
  if (!activeTail) {
507
- activeTail = getNote(getUltimateTailRef(startRef, getField(e, 'tail')));
589
+ activeTail = getNote(getUltimateTailRef(e.archetype, activeStartRef, tailRef));
508
590
  }
509
591
  if (!activeTail) {
510
592
  activeTail = tail;
@@ -532,6 +614,7 @@ export const extendedToLevelData = (data, offset = 0) => {
532
614
  connector.set('activeHead', activeHead);
533
615
  connector.set('activeTail', activeTail);
534
616
  finalEntities.push(connector);
617
+ setInferredActiveHead(segmentHead, activeHead);
535
618
  segments.push({ head: segmentHead, tail });
536
619
  }
537
620
  else {
@@ -568,9 +651,23 @@ export const extendedToLevelData = (data, offset = 0) => {
568
651
  setInferredActiveHead(segmentNote, activeHead);
569
652
  }
570
653
  setInferredActiveHead(activeTail, activeHead);
654
+ for (const skippedNoteRef of skippedNoteRefs) {
655
+ const skippedNote = getNote(skippedNoteRef);
656
+ if (!skippedNote)
657
+ continue;
658
+ skippedNote.set('attachHead', head);
659
+ skippedNote.set('attachTail', tail);
660
+ skippedNote.set('isAttached', 1);
661
+ setInferredActiveHead(skippedNote, activeHead);
662
+ }
571
663
  connectorsByIndex.set(idx, connectorLink);
572
664
  if (e.name)
573
665
  connectorsByName.set(e.name, connectorLink);
666
+ for (const skippedConnector of skippedConnectors) {
667
+ connectorsByIndex.set(skippedConnector.idx, connectorLink);
668
+ if (skippedConnector.e.name)
669
+ connectorsByName.set(skippedConnector.e.name, connectorLink);
670
+ }
574
671
  }
575
672
  function getConn(ref) {
576
673
  if (typeof ref === 'number')
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.16";
10
+ export declare const version = "1.0.18";
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.16';
68
+ export const version = '1.0.18';
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.16",
3
+ "version": "1.0.18",
4
4
  "description": "Perspective-lane rhythm game for Sonolus",
5
5
  "author": "Hyeon2",
6
6
  "repository": {