노래 만들기 수정 — NAS 업로드 완성, Easy 제거 및 ExpertPlus 추가, 다운로드 버그 수정
- NasPublisher: DSM 7.2 multipart body 수동 구성으로 업로드 401 오류 해결 - NasPublisher: 비밀번호 StreamingAssets/nas_config.json 분리, .gitignore 등록 - NasPublisher: staticBaseUrl 포트 8180 → 80 수정 - BeatSageUploader: Easy 난이도 제거, ExpertPlus(.dat) 추가 - NoteData: DifficultyMap에서 easy 제거, expertplus 추가 - SongCreatorManager: toggleEasy → toggleExpertPlus 교체 - SongDetailPanel: btnEasy → btnExpertPlus 교체 - DownloadManager: DownloadHandlerFile 경로 정규화(Path.GetFullPath), mapFile 빈 값 방어 처리 - PersistentXRRig: FindObjectsOfType obsolete 경고 수정 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// 에디터/PC 환경 전용 테스트 보조 스크립트.
|
||||
/// RuntimeInitializeOnLoadMethod로 자동 생성되므로 씬에 직접 추가할 필요 없습니다.
|
||||
/// Quest 빌드 시 자동으로 비활성화됩니다.
|
||||
///
|
||||
/// 기능:
|
||||
/// 1. TrackedDeviceGraphicRaycaster → GraphicRaycaster 교체 (마우스 클릭 활성화)
|
||||
/// 2. Canvas EventCamera 자동 갱신 (클릭 위치 정확도)
|
||||
/// 3. ESC 키로 씬별 뒤로가기
|
||||
/// </summary>
|
||||
public class DesktopUIMode : MonoBehaviour
|
||||
{
|
||||
#if !UNITY_ANDROID || UNITY_EDITOR
|
||||
|
||||
// 어떤 씬에서 Play를 눌러도 자동 실행
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
private static void AutoCreate()
|
||||
{
|
||||
if (FindObjectOfType<DesktopUIMode>() != null) return; // 이미 있으면 생성 안 함
|
||||
|
||||
var go = new GameObject("[DesktopUIMode]");
|
||||
go.AddComponent<DesktopUIMode>();
|
||||
}
|
||||
|
||||
// ESC 뒤로가기 씬 매핑
|
||||
private static readonly System.Collections.Generic.Dictionary<string, string> BackSceneMap =
|
||||
new System.Collections.Generic.Dictionary<string, string>
|
||||
{
|
||||
{ "SongSelect", "Intro" },
|
||||
{ "SongCreator", "Intro" },
|
||||
{ "MapEditorScene", "SongCreator" },
|
||||
{ "Game", "SongSelect" },
|
||||
};
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 중복 방지 (씬에 직접 놓은 경우 AutoCreate와 겹칠 수 있음)
|
||||
if (FindObjectsOfType<DesktopUIMode>().Length > 1)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
PatchCanvases(); // 현재 씬 즉시 패치
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
}
|
||||
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
StartCoroutine(PatchAfterFrame());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator PatchAfterFrame()
|
||||
{
|
||||
yield return null; // Canvas.Awake 이후 실행 보장
|
||||
PatchCanvases();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
RefreshCanvasCameras(); // 매 프레임 worldCamera 갱신 (카메라 초기화 타이밍 보정)
|
||||
|
||||
if (Keyboard.current?.escapeKey.wasPressedThisFrame == true)
|
||||
GoBack();
|
||||
}
|
||||
|
||||
// ── Canvas 패치 ──────────────────────────────────────────
|
||||
|
||||
private static void PatchCanvases()
|
||||
{
|
||||
foreach (var canvas in FindObjectsOfType<Canvas>())
|
||||
{
|
||||
if (canvas.renderMode != RenderMode.WorldSpace) continue;
|
||||
|
||||
// TrackedDeviceGraphicRaycaster → GraphicRaycaster
|
||||
var tracked = canvas.GetComponent("TrackedDeviceGraphicRaycaster");
|
||||
if (tracked != null)
|
||||
{
|
||||
DestroyImmediate(tracked);
|
||||
if (canvas.GetComponent<GraphicRaycaster>() == null)
|
||||
canvas.gameObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
Debug.Log($"[DesktopUIMode] {canvas.name} Raycaster 교체 완료");
|
||||
}
|
||||
}
|
||||
|
||||
RemoveDuplicateAudioListeners();
|
||||
RefreshCanvasCameras();
|
||||
}
|
||||
|
||||
private static void RemoveDuplicateAudioListeners()
|
||||
{
|
||||
var listeners = FindObjectsOfType<AudioListener>();
|
||||
if (listeners.Length <= 1) return;
|
||||
|
||||
// 첫 번째(DontDestroyOnLoad에 없는 것 우선)만 남기고 나머지 제거
|
||||
AudioListener keep = null;
|
||||
foreach (var al in listeners)
|
||||
{
|
||||
if (al.gameObject.scene.name != "DontDestroyOnLoad")
|
||||
{ keep = al; break; }
|
||||
}
|
||||
if (keep == null) keep = listeners[0];
|
||||
|
||||
foreach (var al in listeners)
|
||||
{
|
||||
if (al != keep)
|
||||
{
|
||||
Debug.Log($"[DesktopUIMode] 중복 AudioListener 제거: {al.gameObject.name}");
|
||||
DestroyImmediate(al);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RefreshCanvasCameras()
|
||||
{
|
||||
Camera cam = Camera.main;
|
||||
if (cam == null)
|
||||
{
|
||||
// Camera.main이 없으면 씬에서 직접 찾기 (DontDestroyOnLoad 제외)
|
||||
foreach (var c in FindObjectsOfType<Camera>())
|
||||
{
|
||||
if (c.enabled && c.gameObject.scene.name != "DontDestroyOnLoad")
|
||||
{
|
||||
cam = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cam == null) cam = FindObjectOfType<Camera>(); // 최후 수단
|
||||
if (cam == null) return;
|
||||
|
||||
foreach (var canvas in FindObjectsOfType<Canvas>())
|
||||
{
|
||||
if (canvas.renderMode == RenderMode.WorldSpace && canvas.worldCamera != cam)
|
||||
canvas.worldCamera = cam;
|
||||
}
|
||||
}
|
||||
|
||||
// ── ESC 뒤로가기 ─────────────────────────────────────────
|
||||
|
||||
private static void GoBack()
|
||||
{
|
||||
string current = SceneManager.GetActiveScene().name;
|
||||
if (BackSceneMap.TryGetValue(current, out string target))
|
||||
SceneManager.LoadScene(target);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user