feat: SongCreator 씬 완성 — Beat Sage URL 지원, info.dat 메타데이터 자동 추출

- BeatSageUploader: audio_url 지원(UploadFromUrl), PollAndDownload 공통화, ZIP 500 오류 3회 재시도
- BeatSageConverter: info.dat 파싱(SongMetadata), BPM 자동 감지 → 노트 타이밍 변환에 적용
- SongCreatorManager: title/BPM 필수 입력 제거, 난이도 4개 자동 선택, GenerateFlowFromUrl 버그 수정
- NasPublisher: audioPath null 허용(URL 흐름에서 로컬 파일 없는 경우 스킵)
- .gitignore/.gitattributes 초기 설정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 23:37:34 +09:00
commit 4dad9e5d5b
1068 changed files with 175146 additions and 0 deletions
@@ -0,0 +1,46 @@
using UnityEngine;
namespace VRBeats
{
public class BeatCubeDeadZone : MonoBehaviour
{
[SerializeField] private Transform playerTransform = null;
[SerializeField] private Vector3 offset = Vector3.zero;
private void Awake()
{
Collider collider = GetComponent<Collider>();
if (collider != null)
{
collider.isTrigger = true;
}
}
private void LateUpdate()
{
transform.position = playerTransform.position + offset;
}
private void OnTriggerEnter(Collider collider)
{
Debug.Log( collider.name );
TryDestroyCube(collider);
}
private void TryDestroyCube(Collider collider)
{
VR_BeatCube cube = collider.GetComponent<VR_BeatCube>();
if (cube != null)
{
cube.Kill();
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0efa3b0ee03961a40b9c0e3b566c2a89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/BeatCubeDeadZone.cs
uploadId: 546658
@@ -0,0 +1,26 @@
using UnityEngine;
namespace VRBeats
{
public class DestroyOnBecameInvisible : MonoBehaviour
{
private float maxLifeTime = 10.0f;
private float timer = 0.0f;
private void Update()
{
timer += Time.deltaTime;
if (timer >= maxLifeTime)
Destroy(gameObject);
}
private void OnBecameInvisible()
{
Destroy(gameObject);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 14d13cad99d563d41a70bb80cd85d6c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/DestroyOnBecameInvisible.cs
uploadId: 546658
@@ -0,0 +1,13 @@
using UnityEngine;
namespace VRBeats
{
public class DontDestroyOnLoad : MonoBehaviour
{
private void Start()
{
DontDestroyOnLoad(gameObject);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a4be18cd510d45347a67580051011ba6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/DontDestroyOnLoad.cs
uploadId: 546658
@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Fourdplan
{
public class FaceCamera : MonoBehaviour
{
[SerializeField] private int direction = 1;
[SerializeField] private Transform overrideLookAt = null;
public Transform LookAt { get { return overrideLookAt == null ? Camera.main.transform : overrideLookAt; } }
private void LateUpdate()
{
Vector3 dir = LookAt.forward;
transform.forward = (LookAt.position - transform.position).normalized * direction;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8b4a304d65e2bcc429c6745ee405791e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/FaceCamera.cs
uploadId: 546658
@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FadeEmission : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 00a6f2f67ebd20a4b89fee33839c8fc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/FadeEmission.cs
uploadId: 546658
@@ -0,0 +1,60 @@
using UnityEngine;
using UnityEngine.Events;
namespace VRBeats
{
public class MaterialBindings : MonoBehaviour
{
[SerializeField] private Renderer[] renderArray = null;
[SerializeField] private UnityEvent onSetMaterialColor = null;
public void SetBaseColor(Color c)
{
SetColorBinding("_BaseColor" , c);
}
public void SetEmmisiveColor(Color c)
{
SetColorBinding("_EmissionColor", c );
onSetMaterialColor.Invoke();
}
public Color GetEmmisiveColor()
{
return renderArray[0].material.GetColor("_EmissionColor");
}
public void SetUseEmmisiveIntensity(bool value)
{
SetIntegerBinding("_UseEmissiveIntensity", value ? 1 : 0);
}
private void SetColorBinding(string binding ,Color c)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetColor(binding , c);
}
}
private void SetFloatBinding(string binding, float v)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetFloat(binding, v);
}
}
private void SetIntegerBinding(string binding, int v)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetInt(binding, v);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f1ba20572149b2f45a00f3b6d8191d0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/MaterialBindings.cs
uploadId: 546658
@@ -0,0 +1,44 @@
using UnityEngine;
using UnityEngine.Playables;
using VRBeats.ScriptableEvents;
namespace VRBeats
{
public class PlayableDirectorEvents : MonoBehaviour
{
[SerializeField] private GameEvent onLevelComplete = null;
private PlayableDirector director = null;
private bool alreadyStarted = false;
private bool eventTrigered = false;
private void Awake()
{
director = GetComponent<PlayableDirector>();
}
private void Update()
{
if (!alreadyStarted)
{
alreadyStarted = director.state == PlayState.Playing;
return;
}
if (!eventTrigered && director.time >= director.playableAsset.duration - 0.5f)
{
eventTrigered = true;
onLevelComplete.Invoke();
}
}
public void OnRestart()
{
alreadyStarted = false;
eventTrigered = false;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c2836de0a6bae6947ae91f1c10810aeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/PlayableDirectorEvents.cs
uploadId: 546658
@@ -0,0 +1,33 @@
using UnityEngine;
using UnityEngine.Playables;
namespace VRBeats
{
public class PlayableManager : MonoBehaviour
{
[SerializeField] private TracksDatabase tracks = null;
private PlayableDirector playableDirector = null;
private static int selectedTrackIndex = 0;
private void Awake()
{
playableDirector = GetComponent<PlayableDirector>();
playableDirector.playOnAwake = false;
playableDirector.playableAsset = tracks.TrackList[selectedTrackIndex].playableAsset;
}
private void Start()
{
playableDirector.Play();
}
public static void SetSelectedTrackIndex(int index)
{
selectedTrackIndex = index;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 13fbf4f54fbeb314fbf4b640bf390ac2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/PlayableManager.cs
uploadId: 546658
@@ -0,0 +1,27 @@
using UnityEngine;
namespace VRBeats
{
public class RandomizeRotation : MonoBehaviour
{
[SerializeField] private float minRotation = 0.0f;
[SerializeField] private float maxRotation = 0.0f;
[SerializeField] private Ease ease = Ease.EaseOutExpo;
[SerializeField] private float animTime = 2.0f;
private void Awake()
{
animTime = Random.Range(animTime / 2.0f , animTime);
Rotate();
}
private void Rotate()
{
float rotation = Random.Range(-maxRotation , maxRotation);
transform.RotateTween( Vector3.forward , rotation , animTime).SetEase(ease).SetOnComplete( Rotate );
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3ad3946ef3ac7a24684c416b90596a9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RandomizeRotation.cs
uploadId: 546658
@@ -0,0 +1,73 @@
using UnityEngine;
using System.Collections;
namespace VRBeats
{
public class RotPartController : MonoBehaviour
{
[SerializeField] private Ease ease = Ease.Linear;
[SerializeField] private float animTime = 2.0f;
private Transform[] childArray = null;
private bool open = false;
private void Awake()
{
childArray = new Transform[ transform.childCount ];
for (int n = 0; n < transform.childCount; n++)
{
childArray[n] = transform.GetChild(n);
}
//PlayRotAnimation(10.0f);
//yield return new WaitForSeconds(10.0f);
//Reverse(10.0f);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.J))
{
if (open)
{
Reverse(0.0f);
}
else
{
PlayRotAnimation(10.0f);
}
open = !open;
}
}
public void PlayRotAnimation(float rotAmount)
{
float step = rotAmount;
for (int n = 0; n < childArray.Length; n++)
{
childArray[n].RotateTween(Vector3.forward , step * ( childArray.Length - n ) , animTime ).SetEase(ease);
childArray[n].ScaleTween( new Vector3(1.0f , 1.0f , 0.0f) , animTime ).SetEase(ease);
}
}
public void Reverse(float rotAmount)
{
float step = rotAmount;
for (int n = 0; n < childArray.Length; n++)
{
childArray[n].RotateTween(Vector3.forward, step * (childArray.Length - n), animTime).SetEase(ease);
childArray[n].ScaleTween(new Vector3(1.0f, 1.0f, 4.0f), animTime).SetEase(ease);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 06419d924095a374fa32cb83a753c387
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RotPartController.cs
uploadId: 546658
@@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Platinio.TweenEngine;
namespace VRBeats
{
public class RotationLoop : MonoBehaviour
{
[SerializeField] private float time = 0.0f;
[SerializeField] private float delay = 0.1f;
[SerializeField] private Ease ease = Ease.Linear;
[SerializeField] private Vector3 axis = Vector3.up;
private const float speed = 360.0f;
private void Awake()
{
Rotate();
}
private void Rotate()
{
transform.RotateTween( Vector3.up , 360.0f , time).SetOnComplete(Rotate).SetDelay(delay).SetEase(ease);
/*
PlatinioTween.instance.ValueTween(0.0f , 1.0f , time).SetOnUpdateFloat( delegate (float v)
{
//transform.rotation = Quaternion.Lerp( transform.rotation , Quaternion.Euler( axis * 360.0f ) , v );
transform.Rotate(axis , speed * v * Time.deltaTime);
} ).SetOnComplete( Rotate ).SetDelay(delay).SetEase(ease);*/
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 90b2587544d4e764e8805205ce1cf19a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RotationLoop.cs
uploadId: 546658
@@ -0,0 +1,17 @@
using UnityEngine;
namespace Austral3D
{
public class Rotator : MonoBehaviour
{
[SerializeField] private Vector3 axis = Vector3.zero;
[SerializeField] private float speed = 1.0f;
[SerializeField] private Space space = Space.Self;
private void Update()
{
transform.Rotate(axis , speed * Time.deltaTime , space);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c6c3d54a6acd7b248a149b16ce058f90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/Rotator.cs
uploadId: 546658
@@ -0,0 +1,40 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VRBeats
{
public class SetNoEmmisiveColor : MonoBehaviour
{
[SerializeField] private Renderer[] renderArray = null;
[SerializeField] private VR_BeatCubeSpawneable spanwneable = null;
private Color SideColor
{
get
{
if (spanwneable.ColorSide == ColorSide.Right)
return VR_BeatManager.instance.GameSettings.RightColor;
return VR_BeatManager.instance.GameSettings.LeftColor;
}
}
public void SetColor()
{
for (int n = 0; n < renderArray.Length; n++)
{
Material[] materialArray = renderArray[n].materials;
for (int j = 0; j < materialArray.Length; j++)
{
materialArray[j].SetColor("_BaseColor", SideColor);
}
renderArray[n].materials = materialArray;
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 19fceb8ad5d0f0a428b8cab8c0e5a72f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/SetNoEmmisiveColor.cs
uploadId: 546658
+40
View File
@@ -0,0 +1,40 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VRBeats
{
public class Spark : MonoBehaviour
{
[SerializeField] MaterialBindings materialBindings = null;
[SerializeField] private float glowEffect = 0.5f;
[SerializeField] private float scaleTime = 1.5f;
[SerializeField] private float moveTime = 1.5f;
[SerializeField] private float targetScale = 500.0f;
public void Construct(Color c)
{
materialBindings.SetUseEmmisiveIntensity(false);
materialBindings.SetEmmisiveColor(c * glowEffect);
PlayAnimation();
}
private void OnDestroy()
{
gameObject.CancelAllTweens();
}
private void PlayAnimation()
{
transform.ScaleY(targetScale, scaleTime).SetEase(Ease.EaseOutExpo).SetOnComplete(delegate
{
transform.Move(transform.position + Vector3.up * targetScale, moveTime).SetOnComplete(delegate
{
Destroy(gameObject);
}).SetOwner(gameObject);
}).SetOwner(gameObject); ;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 999236c5aa99b6048a20b501bd8d4935
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/Spark.cs
uploadId: 546658
@@ -0,0 +1,33 @@
using UnityEngine;
namespace VRBeats
{
public class VolumeSingleton : MonoBehaviour
{
private static VolumeSingleton Instance;
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
VolumeSingleton[] instancesArray = FindObjectsOfType<VolumeSingleton>();
foreach (var volumeSingleton in instancesArray)
{
if (volumeSingleton != Instance)
{
Destroy(volumeSingleton.gameObject);
}
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f1cf1a69a2048dc48b769f7289ca6b72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/VolumeSingleton.cs
uploadId: 546658