nise/nise-frontend/src/corelib/components/replay-viewer/decode-beatmap.ts

126 lines
3.0 KiB
TypeScript
Raw Normal View History

2024-02-29 02:02:14 +00:00
export enum HitObjectType {
HitCircle = 1,
Slider = 2,
Spinner = 8
}
export type HitObject = {
x: number;
y: number;
time: number;
type: number;
hitSound: number;
objectParams: string;
hitSample: string;
currentCombo: number;
2024-02-29 02:02:14 +00:00
};
export interface BeatmapDifficulty {
hpDrainRate: number;
circleSize: number;
overralDifficulty: number;
approachRate: number;
sliderMultiplier: number;
sliderTickRate: number;
}
export function parseBeatmapDifficulty(beatmap: string): BeatmapDifficulty {
const lines = beatmap.split('\n');
let recording = false;
const difficulty: Partial<BeatmapDifficulty> = {};
for (const line of lines) {
if (line.trim() === '[Difficulty]') {
recording = true;
continue;
}
if (!recording) continue;
if (line.startsWith('[')) break;
const parts = line.split(':');
if (parts.length < 2) continue;
switch (parts[0]) {
case 'HPDrainRate':
difficulty.hpDrainRate = parseFloat(parts[1]);
break;
case 'CircleSize':
difficulty.circleSize = parseFloat(parts[1]);
break;
case 'OverallDifficulty':
difficulty.overralDifficulty = parseFloat(parts[1]);
break;
case 'ApproachRate':
difficulty.approachRate = parseFloat(parts[1]);
break;
case 'SliderMultiplier':
difficulty.sliderMultiplier = parseFloat(parts[1]);
break;
case 'SliderTickRate':
difficulty.sliderTickRate = parseFloat(parts[1]);
break;
}
}
return difficulty as BeatmapDifficulty;
}
2024-02-29 02:02:14 +00:00
export function parseHitObjects(beatmap: string): any[] {
const lines = beatmap.split('\n');
let recording = false;
const hitObjects = [];
let currentCombo = 1;
2024-02-29 02:02:14 +00:00
for (const line of lines) {
if (line.trim() === '[HitObjects]') {
recording = true;
continue;
}
if (!recording) continue;
if (line.startsWith('[')) break;
const parts = line.split(',');
if (parts.length < 5) continue;
const type = parseInt(parts[3], 10);
const isNewCombo = type & (1 << 2); // Bit at index 2 for new combo
if (isNewCombo) {
currentCombo = 1; // Reset combo
} else {
// If not the start of a new combo, increment the current combo
currentCombo++;
}
2024-02-29 02:02:14 +00:00
const hitObject = {
x: parseInt(parts[0], 10),
y: parseInt(parts[1], 10),
time: parseInt(parts[2], 10),
type: getTypeFromFlag(type),
hitSound: parseInt(parts[4], 10),
objectParams: parts[5],
hitSample: parts.length > 6 ? parts[6] : '0:0:0:0:',
currentCombo: currentCombo
2024-02-29 02:02:14 +00:00
};
if (isNewCombo) {
// Reset currentCombo after assigning to hitObject if it's the start of a new combo
currentCombo = 1;
}
2024-02-29 02:02:14 +00:00
hitObjects.push(hitObject);
}
return hitObjects;
}
function getTypeFromFlag(flag: number): HitObjectType | null {
if (flag & HitObjectType.HitCircle) return HitObjectType.HitCircle;
if (flag & HitObjectType.Slider) return HitObjectType.Slider;
if (flag & HitObjectType.Spinner) return HitObjectType.Spinner;
return null;
}