Files
BeatSaber/md/VRBeatSaber_BeatSage_Integration_Spec.md
T

158 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VRBeatSaber 기술 기획서
> 비트세이지 데이터 연동 온디맨드 스트리밍 및 에디터 통합 시스템
**작성일:** 2026년 5월 20일 | **문서 버전:** v1.0 | **프로젝트:** VRBeatSaber
---
## 1. 개요 (Introduction)
본 시스템은 오큘러스 퀘스트(독립형 VR) 하드웨어의 제한된 컴퓨팅 자원(CPU, RAM) 및 저장 공간 한계를 극복하기 위해 설계된 플랫폼 형태의 리듬 게임 인프라이다.
기기 내부에 대용량 음원을 상주시키는 대신, 필요 시 서버에서 동적으로 다운로드(On-Demand)하고, 외부의 무료 오토 매핑 서비스인 **비트세이지(Beat Sage)**의 연산 결과물(비트세이버 표준 포맷)을 흡수하여 구현한다.
이를 통해 자체적인 AI 모델 구축 비용(서버 유지비, GPU 연산 리소스)을 **0원으로 절감**하는 동시에 대량의 하이퀄리티 맵 데이터를 빠르게 수급할 수 있다. 개발자는 파이썬 머신러닝 레이어를 직접 다루지 않고, 오직 유니티 C# 환경 내에서 비트세이버 포맷을 자체 JSON 포맷으로 변환하는 데이터 컨버터 및 온디맨드 다운로드 시스템 구축에만 집중한다.
---
## 2. 전체 데이터 파이프라인 (Data Pipeline)
전체 워크플로우는 다음 4단계 구조를 가진다.
```
[외부 수급] → [서버 저장 및 관리] → [유니티 다운로드 및 포맷 변환] → [에디터 수정/인게임 플레이]
```
| 단계 | 구성요소 | 역할 |
|------|----------|------|
| 1 | **비트세이지 웹사이트** | 유저/개발자가 웹 인터페이스로 음원 입력 → 무료 AI 매핑 → 맵 데이터 패키지(`.zip`) 확보 |
| 2 | **자체 백엔드 서버 (Synology NAS)** | Web Station 정적 웹서버로 곡 메타데이터 리스트(`songs.json`), 음원 파일(`.mp3`), 비트세이지 원본 데이터 보관 |
| 3 | **유니티 클라이언트** | `UnityWebRequest`로 무선 네트워크 스트리밍, 오큘러스 퀘스트 임시 경로에 다운로드 후 내부 컨버터로 자체 포맷 변환 |
| 4 | **맵 에디터 통합** | 변환 완료된 데이터를 `MapEditor` 씬으로 로드, 기계 생성 초안(80%) 기반으로 개발자가 정교하게 디렉팅 및 수정 |
---
## 3. 데이터 구조 비교 및 변환 명세 (Data Mapping Spec)
### 3.1 비트세이지 결과물 포맷 (비트세이버 표준 v2 포맷)
비트세이지에서 생성된 압축파일 내 `Expert.dat` 등의 파일 구조:
```json
{
"_version": "2.0.0",
"_notes": [
{ "_time": 1.5, "_lineIndex": 0, "_lineLayer": 0, "_type": 0, "_cutDirection": 1 },
{ "_time": 2.3, "_lineIndex": 3, "_lineLayer": 0, "_type": 1, "_cutDirection": 0 }
]
}
```
### 3.2 현재 프로젝트 자체 포맷 (`Map_[곡이름].json`)
유니티 직렬화 및 기존 인게임 스폰 프레임워크가 요구하는 데이터 구조:
```json
{
"target": [
{ "time": 0.75, "position": 0, "colorType": 0 },
{ "time": 1.15, "position": 3, "colorType": 1 }
]
}
```
### 3.3 구조 변환 규칙 (Mapping Rules)
| 비트세이지 원본 필드 | 자체 프로젝트 매핑 필드 | 변환 연산 및 예외 처리 규칙 |
|---------------------|------------------------|--------------------------|
| `_time` (float) | `time` (float) | 비트 단위 → 초 단위 환산<br>**`Time(s) = (_time × 60) / BPM`** |
| `_lineIndex` (int) | `position` (int) | 가로 라인 0~3 범위 1:1 매칭 |
| `_type` (int) | `colorType` (int) | `0`: 빨간색 노트(왼손)<br>`1`: 파란색 노트(오른손)<br>폭탄(`value: 3`)은 `continue` 처리로 필터링 |
> ⚠️ **주의사항:** 비트세이지의 시간 축은 절대적인 초 단위가 아닌 BPM에 종속적인 비트 카운트이므로, 변환 연산 시 음원의 정확한 메타데이터 **BPM 값이 필수적으로 제공**되어야 동기화가 유지된다.
---
## 4. 유니티 클라이언트 코어 구현 (C#)
네트워크 비동기 수신처리와 수신 즉시 인메모리/로컬 캐시 직렬화 변환을 수행하기 위한 DTO 및 핵심 컨버터 C# 스크립트 설계 구조이다.
### 4.1 수신용 데이터 구조 클래스
```csharp
using System;
using System.Collections.Generic;
[Serializable]
public class BeatSageRoot
{
public string _version;
public List<BeatSageNote> _notes;
}
[Serializable]
public class BeatSageNote
{
public float _time; // 비트 단위 시간
public int _lineIndex; // 가로 위치 (0~3)
public int _lineLayer; // 세로 위치
public int _type; // 타입 (0: Red, 1: Blue)
public int _cutDirection; // 베는 방향
}
```
### 4.2 포맷 컨버터 코어 로직 (`BeatSageConverter.cs`)
```csharp
using UnityEngine;
using System.Collections.Generic;
public class BeatSageConverter : MonoBehaviour
{
/// <summary>
/// 비트세이지 .dat 텍스트 데이터를 우리 게임의 NoteData 리스트로 변환합니다.
/// </summary>
public List<NoteData> ConvertBeatSageToMyFormat(string rawJson, float songBPM)
{
BeatSageRoot sageData = JsonUtility.FromJson<BeatSageRoot>(rawJson);
List<NoteData> convertedNotes = new List<NoteData>();
if (sageData == null || sageData._notes == null) return convertedNotes;
foreach (var sageNote in sageData._notes)
{
// 일반 노트(0: 빨강, 1: 파랑)만 처리하고 나머지 오브젝트는 제외
if (sageNote._type != 0 && sageNote._type != 1) continue;
// BPM 공식을 대입하여 실제 게임 시간(초) 계산
float realTimeSeconds = (sageNote._time * 60f) / songBPM;
NoteData myNote = new NoteData
{
time = realTimeSeconds,
position = sageNote._lineIndex,
colorType = sageNote._type
};
convertedNotes.Add(myNote);
}
Debug.Log($"[컨버터] 비트세이지 포맷 변환 성공: {convertedNotes.Count}개 노트 생성됨.");
return convertedNotes;
}
}
```
---
## 5. 디바이스 스토리지 최적화 (Oculus Quest)
### 온디맨드 다운로드 패턴
유저가 인게임 UI 또는 맵 에디터에서 특정 곡을 선택하여 트리거하기 전까지는 음원(`.mp3`)과 데이터(`.json`) 파일을 다운로드하지 않아 앱 기본 설치 용량을 최소화한다.
### 임시 캐시 경로 활용
모든 스트리밍 다운로드 리소스는 `Application.temporaryCachePath`에 저장하여 오큘러스 내부 저장소의 파일 오염을 방지하며, OS의 메모리 부족 시 정리 가능한 대상 영역으로 권한을 위임한다.
### LRU (Least Recently Used) 삭제 메커니즘
게임 또는 툴 초기화 시 캐시 디렉터리 용량을 확인하여 **누적 용량이 1GB를 초과**할 경우, 파일 시스템의 '최근 접근 시간(Last Access Time)'이 가장 오래된 곡 폴더부터 순차적으로 `Directory.Delete`로 자동 소거한다.