277 lines
9.8 KiB
C#
277 lines
9.8 KiB
C#
using UnityEngine;
|
|
using System.IO;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
using Streamingle.Debug;
|
|
using System.Linq;
|
|
|
|
namespace Streamingle
|
|
{
|
|
public class StreamingleAvatarImport : MonoBehaviour
|
|
{
|
|
private Dictionary<string, GameObject> loadedAvatars = new Dictionary<string, GameObject>();
|
|
private StreamingleDebugWindow debugWindow;
|
|
|
|
[SerializeField]
|
|
public bool createDebugUI = false;
|
|
|
|
/// <summary>
|
|
/// 스트리밍글 아바타 파일을 비동기적으로 로드합니다.
|
|
/// </summary>
|
|
/// <param name="filePath">로드할 .streamingle 파일의 전체 경로</param>
|
|
/// <param name="parentTransform">로드된 아바타가 배치될 부모 Transform (null인 경우 월드 좌표계에 생성)</param>
|
|
/// <returns></returns>
|
|
public IEnumerator LoadAvatarAsync(string filePath, Transform parentTransform = null)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
{
|
|
UpdateDebugText($"파일을 찾을 수 없음: {filePath}");
|
|
UnityEngine.Debug.LogError($"파일을 찾을 수 없습니다: {filePath}");
|
|
yield break;
|
|
}
|
|
|
|
string avatarKey = Path.GetFileNameWithoutExtension(filePath);
|
|
UpdateDebugText($"아바타 로드 중: {avatarKey}");
|
|
|
|
if (loadedAvatars.ContainsKey(avatarKey))
|
|
{
|
|
Destroy(loadedAvatars[avatarKey]);
|
|
loadedAvatars.Remove(avatarKey);
|
|
}
|
|
|
|
AssetBundle avatarBundle = null;
|
|
|
|
// AssetBundle 로드
|
|
AssetBundleCreateRequest bundleRequest = null;
|
|
try
|
|
{
|
|
bundleRequest = AssetBundle.LoadFromFileAsync(filePath);
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
UpdateDebugText($"AssetBundle 로드 실패: {e.Message}");
|
|
UnityEngine.Debug.LogError($"AssetBundle 로드 실패: {e.Message}");
|
|
yield break;
|
|
}
|
|
|
|
yield return bundleRequest;
|
|
|
|
if (bundleRequest.assetBundle == null)
|
|
{
|
|
UpdateDebugText("AssetBundle 로드 실패");
|
|
UnityEngine.Debug.LogError("AssetBundle 로드 실패");
|
|
yield break;
|
|
}
|
|
|
|
avatarBundle = bundleRequest.assetBundle;
|
|
|
|
// 아바타 프리팹 로드
|
|
AssetBundleRequest prefabRequest = null;
|
|
try
|
|
{
|
|
string[] assetNames = avatarBundle.GetAllAssetNames();
|
|
UnityEngine.Debug.Log($"번들 내 에셋 목록: {string.Join(", ", assetNames)}");
|
|
|
|
// 번들 내 첫 번째 프리팹을 로드하거나, 특정 이름 패턴을 가진 프리팹을 찾아서 로드
|
|
string prefabPath = assetNames.FirstOrDefault(name => name.EndsWith(".prefab"));
|
|
if (string.IsNullOrEmpty(prefabPath))
|
|
{
|
|
UpdateDebugText("프리팹을 찾을 수 없습니다.");
|
|
UnityEngine.Debug.LogError("번들 내에서 프리팹을 찾을 수 없습니다.");
|
|
if (avatarBundle != null)
|
|
avatarBundle.Unload(false);
|
|
yield break;
|
|
}
|
|
|
|
prefabRequest = avatarBundle.LoadAssetAsync<GameObject>(prefabPath);
|
|
if (prefabRequest == null)
|
|
{
|
|
UpdateDebugText("프리팹 로드 요청 생성 실패");
|
|
UnityEngine.Debug.LogError("프리팹 로드 요청을 생성할 수 없습니다.");
|
|
if (avatarBundle != null)
|
|
avatarBundle.Unload(false);
|
|
yield break;
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
UpdateDebugText($"프리팹 로드 실패: {e.Message}");
|
|
UnityEngine.Debug.LogError($"프리팹 로드 실패: {e.Message}");
|
|
if (avatarBundle != null)
|
|
avatarBundle.Unload(false);
|
|
yield break;
|
|
}
|
|
|
|
yield return prefabRequest;
|
|
|
|
if (prefabRequest.asset == null)
|
|
{
|
|
UpdateDebugText("아바타 프리팹 로드 실패");
|
|
UnityEngine.Debug.LogError("아바타 프리팹 로드 실패");
|
|
if (avatarBundle != null)
|
|
avatarBundle.Unload(false);
|
|
yield break;
|
|
}
|
|
|
|
try
|
|
{
|
|
// 아바타 인스턴스화
|
|
GameObject avatarPrefab = prefabRequest.asset as GameObject;
|
|
GameObject avatar = Instantiate(avatarPrefab, parentTransform);
|
|
avatar.name = avatarKey;
|
|
loadedAvatars.Add(avatarKey, avatar);
|
|
|
|
UpdateDebugText($"아바타 로드 완료: {avatarKey}");
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
UpdateDebugText($"아바타 생성 실패: {e.Message}");
|
|
UnityEngine.Debug.LogError($"아바타 생성 실패: {e.Message}");
|
|
}
|
|
finally
|
|
{
|
|
if (avatarBundle != null)
|
|
avatarBundle.Unload(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 특정 아바타를 제거합니다.
|
|
/// </summary>
|
|
public void UnloadAvatar(string avatarKey)
|
|
{
|
|
if (loadedAvatars.ContainsKey(avatarKey))
|
|
{
|
|
Destroy(loadedAvatars[avatarKey]);
|
|
loadedAvatars.Remove(avatarKey);
|
|
UpdateDebugText($"아바타 언로드됨: {avatarKey}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 아바타를 제거합니다.
|
|
/// </summary>
|
|
public void UnloadAllAvatars()
|
|
{
|
|
foreach (var avatar in loadedAvatars.Values)
|
|
{
|
|
if (avatar != null)
|
|
{
|
|
Destroy(avatar);
|
|
}
|
|
}
|
|
loadedAvatars.Clear();
|
|
UpdateDebugText("모든 아바타가 언로드됨");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 특정 아바타 게임오브젝트를 반환합니다.
|
|
/// </summary>
|
|
public GameObject GetLoadedAvatar(string avatarKey)
|
|
{
|
|
return loadedAvatars.ContainsKey(avatarKey) ? loadedAvatars[avatarKey] : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 로드된 모든 아바타의 목록을 반환합니다.
|
|
/// </summary>
|
|
public Dictionary<string, GameObject> GetLoadedAvatars()
|
|
{
|
|
return new Dictionary<string, GameObject>(loadedAvatars);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (createDebugUI)
|
|
{
|
|
debugWindow = StreamingleDebugWindow.Create(this, () => OpenFileBrowser());
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (debugWindow != null)
|
|
{
|
|
debugWindow.UnregisterImporter(this);
|
|
}
|
|
// 먼저 모든 아바타를 언로드
|
|
foreach (var avatar in loadedAvatars.Values)
|
|
{
|
|
if (avatar != null)
|
|
{
|
|
Destroy(avatar);
|
|
}
|
|
}
|
|
loadedAvatars.Clear();
|
|
}
|
|
|
|
private void UpdateDebugText(string status)
|
|
{
|
|
if (createDebugUI && debugWindow != null)
|
|
{
|
|
debugWindow.UpdateDebugStatus();
|
|
}
|
|
}
|
|
|
|
private void OpenFileBrowser()
|
|
{
|
|
#if UNITY_EDITOR
|
|
string path = UnityEditor.EditorUtility.OpenFilePanel("아바타 로드", "", "streamingle");
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
StartCoroutine(LoadAvatarAsync(path));
|
|
}
|
|
#else
|
|
// 빌드된 게임에서는 StandaloneFileBrowser 등의 써드파티 에셋을 사용하거나
|
|
// 특정 폴더에서만 로드하도록 구현해야 합니다.
|
|
UnityEngine.Debug.LogWarning("빌드된 게임에서는 파일 브라우저가 지원되지 않습니다.");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// 파일 경로를 통해 아바타를 직접 로드합니다.
|
|
/// </summary>
|
|
public void LoadAvatarFromPath(string path)
|
|
{
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
StartCoroutine(LoadAvatarAsync(path));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 사용 편의성을 위한 정적 클래스
|
|
public static class StreamingleAvatarLoader
|
|
{
|
|
/// <summary>
|
|
/// 간단한 아바타 로드를 위한 정적 메서드
|
|
/// </summary>
|
|
public static StreamingleAvatarImport CreateLoader(bool withDebugUI = false)
|
|
{
|
|
GameObject loaderObject = new GameObject("StreamingleAvatarLoader");
|
|
var loader = loaderObject.AddComponent<StreamingleAvatarImport>();
|
|
loader.createDebugUI = withDebugUI;
|
|
return loader;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 파일 브라우저를 통해 아바타를 로드합니다.
|
|
/// </summary>
|
|
public static void LoadAvatarWithFileBrowser(StreamingleAvatarImport loader)
|
|
{
|
|
#if UNITY_EDITOR
|
|
string path = UnityEditor.EditorUtility.OpenFilePanel("아바타 로드", "", "streamingle");
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
loader.LoadAvatarFromPath(path);
|
|
}
|
|
#else
|
|
UnityEngine.Debug.LogWarning("빌드된 게임에서는 파일 브라우저가 지원되지 않습니다.");
|
|
#endif
|
|
}
|
|
}
|
|
}
|