376 lines
11 KiB
C#

using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using Streamingle;
using Newtonsoft.Json;
public class AvatarOutfitController : MonoBehaviour, IController
{
#region Classes
[System.Serializable]
public class AvatarData
{
[Header("Avatar Settings")]
public string avatarName = "New Avatar";
public GameObject avatarObject;
[Header("Outfit Settings")]
public OutfitData[] outfits = new OutfitData[0];
// 현재 착용 중인 의상 인덱스
[SerializeField] private int currentOutfitIndex = 0;
public int CurrentOutfitIndex => currentOutfitIndex;
public OutfitData CurrentOutfit => outfits != null && outfits.Length > currentOutfitIndex ? outfits[currentOutfitIndex] : null;
public AvatarData(string name)
{
avatarName = name;
outfits = new OutfitData[0];
}
public void SetOutfit(int outfitIndex)
{
if (outfits == null || outfitIndex < 0 || outfitIndex >= outfits.Length)
{
Debug.LogWarning($"[AvatarData] 잘못된 의상 인덱스: {outfitIndex}");
return;
}
// 현재 의상 제거
if (CurrentOutfit != null)
{
CurrentOutfit.RemoveOutfit();
}
// 새 의상 적용
currentOutfitIndex = outfitIndex;
if (CurrentOutfit != null)
{
CurrentOutfit.ApplyOutfit();
Debug.Log($"[AvatarData] {avatarName} 의상 변경: {CurrentOutfit.outfitName}");
}
}
public override string ToString() => avatarName;
}
[System.Serializable]
public class OutfitData
{
[Header("Outfit Info")]
public string outfitName = "New Outfit";
[Header("Clothing GameObjects")]
public GameObject[] clothingObjects = new GameObject[0]; // 활성화할 의상 오브젝트들
public GameObject[] hideObjects = new GameObject[0]; // 비활성화할 오브젝트들 (기본 의상 등)
public void ApplyOutfit()
{
// 의상 오브젝트들 활성화
foreach (var obj in clothingObjects)
{
if (obj != null) obj.SetActive(true);
}
// 숨겨야 할 오브젝트들 비활성화
foreach (var obj in hideObjects)
{
if (obj != null) obj.SetActive(false);
}
}
public void RemoveOutfit()
{
// 의상 오브젝트들 비활성화
foreach (var obj in clothingObjects)
{
if (obj != null) obj.SetActive(false);
}
// 숨겨진 오브젝트들 다시 활성화
foreach (var obj in hideObjects)
{
if (obj != null) obj.SetActive(true);
}
}
}
#endregion
#region Events
public delegate void AvatarOutfitChangedEventHandler(AvatarData avatar, OutfitData oldOutfit, OutfitData newOutfit);
public event AvatarOutfitChangedEventHandler OnAvatarOutfitChanged;
#endregion
#region Fields
[SerializeField] public List<AvatarData> avatars = new List<AvatarData>();
[Header("Avatar Control Settings")]
[SerializeField] private bool autoFindAvatars = false;
[SerializeField] private string avatarTag = "Avatar";
private AvatarData currentAvatar;
private StreamDeckServerManager streamDeckManager;
#endregion
#region Properties
public AvatarData CurrentAvatar => currentAvatar;
public int CurrentAvatarIndex => avatars.IndexOf(currentAvatar);
#endregion
#region Unity Messages
private void Awake()
{
InitializeAvatars();
// StreamDeckServerManager 찾기
streamDeckManager = FindObjectOfType<StreamDeckServerManager>();
if (streamDeckManager == null)
{
Debug.LogWarning("[AvatarOutfitController] StreamDeckServerManager를 찾을 수 없습니다. 스트림덱 연동이 비활성화됩니다.");
}
}
#endregion
#region Initialization
public void InitializeAvatars()
{
if (avatars == null)
{
avatars = new List<AvatarData>();
}
if (autoFindAvatars && avatars.Count == 0)
{
// "Avatar" 태그가 붙은 모든 오브젝트를 찾아서 아바타로 등록
var avatarObjects = GameObject.FindGameObjectsWithTag(avatarTag);
foreach (var avatarObj in avatarObjects)
{
var avatar = new AvatarData(avatarObj.name);
avatar.avatarObject = avatarObj;
avatars.Add(avatar);
}
Debug.Log($"[AvatarOutfitController] {avatars.Count}개의 아바타를 자동으로 찾았습니다.");
}
// 유효하지 않은 아바타 제거
avatars.RemoveAll(avatar => avatar == null || avatar.avatarObject == null);
// 첫 번째 아바타를 기본으로 설정
if (avatars.Count > 0 && currentAvatar == null)
{
currentAvatar = avatars[0];
}
Debug.Log($"[AvatarOutfitController] 총 {avatars.Count}개의 아바타가 등록되었습니다.");
}
#endregion
#region Public Methods
public void Set(int index)
{
// IController 인터페이스 구현 - 첫 번째 아바타의 특정 의상으로 설정
if (avatars.Count > 0)
{
SetAvatarOutfit(0, index);
}
else
{
Debug.LogWarning("[AvatarOutfitController] 설정할 아바타가 없습니다.");
}
}
public void SetAvatarOutfit(int avatarIndex, int outfitIndex)
{
if (avatarIndex < 0 || avatarIndex >= avatars.Count)
{
Debug.LogWarning($"[AvatarOutfitController] 잘못된 아바타 인덱스: {avatarIndex}");
return;
}
var avatar = avatars[avatarIndex];
var oldOutfit = avatar.CurrentOutfit;
avatar.SetOutfit(outfitIndex);
// 이벤트 발생
OnAvatarOutfitChanged?.Invoke(avatar, oldOutfit, avatar.CurrentOutfit);
// StreamDeck에 알림
NotifyAvatarOutfitChanged(avatar);
Debug.Log($"[AvatarOutfitController] 아바타 의상 변경: {avatar.avatarName} -> {avatar.CurrentOutfit?.outfitName}");
}
public void AddAvatar(string avatarName, GameObject avatarObject = null)
{
var newAvatar = new AvatarData(avatarName);
if (avatarObject != null)
{
newAvatar.avatarObject = avatarObject;
}
avatars.Add(newAvatar);
NotifyAvatarOutfitChanged(newAvatar);
Debug.Log($"[AvatarOutfitController] 아바타 추가: {avatarName}");
}
public void RemoveAvatar(int index)
{
if (index < 0 || index >= avatars.Count) return;
var removedAvatar = avatars[index];
avatars.RemoveAt(index);
// 현재 아바타가 제거된 경우 첫 번째 아바타로 변경
if (removedAvatar == currentAvatar)
{
currentAvatar = avatars.Count > 0 ? avatars[0] : null;
}
Debug.Log($"[AvatarOutfitController] 아바타 제거: {removedAvatar.avatarName}");
}
#endregion
#region StreamDeck Integration
private void NotifyAvatarOutfitChanged(AvatarData avatar)
{
if (streamDeckManager != null)
{
streamDeckManager.NotifyAvatarOutfitChanged();
}
}
public AvatarOutfitListData GetAvatarOutfitListData()
{
return new AvatarOutfitListData
{
avatar_count = avatars.Count,
avatars = avatars.Select((a, i) => new AvatarPresetData
{
index = i,
name = a.avatarName,
current_outfit_index = a.CurrentOutfitIndex,
current_outfit_name = a.CurrentOutfit?.outfitName ?? "없음",
outfits = a.outfits?.Select((o, oi) => new OutfitPresetData
{
index = oi,
name = o.outfitName
}).ToArray() ?? new OutfitPresetData[0],
hotkey = "스트림덱 전용"
}).ToArray(),
current_avatar_index = CurrentAvatarIndex
};
}
public AvatarOutfitStateData GetCurrentAvatarOutfitState()
{
if (currentAvatar == null) return null;
return new AvatarOutfitStateData
{
current_avatar_index = CurrentAvatarIndex,
avatar_name = currentAvatar.avatarName,
current_outfit_index = currentAvatar.CurrentOutfitIndex,
current_outfit_name = currentAvatar.CurrentOutfit?.outfitName ?? "없음",
total_avatars = avatars.Count
};
}
public string GetAvatarOutfitListJson()
{
return JsonConvert.SerializeObject(GetAvatarOutfitListData());
}
public string GetAvatarOutfitStateJson()
{
return JsonConvert.SerializeObject(GetCurrentAvatarOutfitState());
}
#endregion
#region Data Classes
[System.Serializable]
public class OutfitPresetData
{
public int index;
public string name;
}
[System.Serializable]
public class AvatarPresetData
{
public int index;
public string name;
public int current_outfit_index;
public string current_outfit_name;
public OutfitPresetData[] outfits;
public string hotkey;
}
[System.Serializable]
public class AvatarOutfitListData
{
public int avatar_count;
public AvatarPresetData[] avatars;
public int current_avatar_index;
}
[System.Serializable]
public class AvatarOutfitStateData
{
public int current_avatar_index;
public string avatar_name;
public int current_outfit_index;
public string current_outfit_name;
public int total_avatars;
}
#endregion
#region IController Implementation
public string GetControllerId()
{
return "avatar_outfit_controller";
}
public string GetControllerName()
{
return "Avatar Outfit Controller";
}
public object GetControllerData()
{
return GetAvatarOutfitListData();
}
public void ExecuteAction(string actionId, object parameters)
{
switch (actionId)
{
case "set_avatar_outfit":
if (parameters is Dictionary<string, object> setParams)
{
if (setParams.ContainsKey("avatar_index") && setParams.ContainsKey("outfit_index"))
{
int avatarIndex = Convert.ToInt32(setParams["avatar_index"]);
int outfitIndex = Convert.ToInt32(setParams["outfit_index"]);
SetAvatarOutfit(avatarIndex, outfitIndex);
}
}
break;
default:
Debug.LogWarning($"[AvatarOutfitController] 알 수 없는 액션: {actionId}");
break;
}
}
#endregion
}