-
Notifications
You must be signed in to change notification settings - Fork 0
Feature: 캐릭터 모델 기능 추가 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- 치와짱 모델은 유료 모델이므로 유출 방지, 제작자에게 손해를 입히지 않도록 유의한다. - 개발자인 경우 치와짱 모델을 요청하세요
|
Caution Review failedThe pull request is closed. Walkthrough새 ChatSystemManager 및 ChatMessageQueue 추가, CharacterActionController/CharacterManager/CharacterModelLoader 및 Live2D 해상도 스케일링(ResolutionManager/Live2DModelScaler/CameraResolutionScaler/ResolutionModelScaleConfig) 도입; 기존 Live2D 컨트롤러·매니저·테스트 다수 삭제; 오디오 및 채팅 DTO 변경, .gitignore·메타·GUID 조정. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant TextInput as TextInputView
participant ChatMgr as ChatSystemManager
participant API as ChatApiService
participant WS as WebSocketManager
participant UI as ChatBubblePanel
participant Audio as AudioManager
participant Char as CharacterManager
User->>TextInput: Send message
TextInput->>ChatMgr: SendUserMessage(message)
ChatMgr->>Char: PlayAction(Listen)
ChatMgr->>API: Send request
WS-->>ChatMgr: OnChatMessageReceived(ChatMessage)
ChatMgr->>UI: Show character bubble
alt voice present
ChatMgr->>Audio: Play(VoiceData)
end
ChatMgr->>Char: PlayAction(Talk)
ChatMgr-->>ChatMgr: Wait (voice length or default)
ChatMgr->>Char: PlayAction(Idle)
ChatMgr-->>UI: OnConversationEnd
sequenceDiagram
autonumber
participant Sys as SystemManager
participant Audio as AudioManager
participant CharMgr as CharacterManager
participant Loader as CharacterModelLoader
participant Registry as Live2DModelRegistry
Sys->>Audio: Initialize()
Audio-->>Sys: OnInitialized
Sys->>CharMgr: Initialize()
CharMgr->>Loader: Initialize(registry, voiceSource)
CharMgr->>Loader: LoadAndInitializeModelAsync("zero", parent)
Loader->>Registry: Get config
Loader-->>CharMgr: GameObject (initialized, inactive)
CharMgr->>CharMgr: Activate & cache action controller
sequenceDiagram
autonumber
participant ResMgr as ResolutionManager
participant Scaler as Live2DModelScaler
participant Cam as CameraResolutionScaler
Note over ResMgr,Scaler: 해상도 변경 발생 시
ResMgr->>ResMgr: CalculateScale()
ResMgr->>Scaler: ApplyScaleWithPreCalculatedScale(scale)
Cam->>Cam: ApplyCameraScale()
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: CodeRabbit UI 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (7)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 27
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
Assets/Core/Audio/AudioRecorder.cs (3)
316-321: 런타임에서DestroyImmediate사용은 안전하지 않습니다 —Destroy로 교체하세요.
DestroyImmediate는 에디터 전용 사용이 권장되며, 플레이 모드/런타임에서 예기치 않은 부작용을 유발할 수 있습니다. 여기서는 프레임 말에 안전하게 파괴되는Destroy가 적절합니다.권장(diff):
- if (_recordingClip != null) - { - DestroyImmediate(_recordingClip); - } + if (_recordingClip != null) + { + Destroy(_recordingClip); + }
96-107:Microphone.Start실패(null 반환) 경로를 처리하세요.일부 환경에서
Microphone.Start가 예외 없이 null을 반환할 수 있습니다. 현재는 null이어도OnRecordingStarted가 호출되어 UX가 혼동될 수 있습니다.권장(diff):
- _isRecording = true; - _recordingStartTime = Time.time; - - _recordingClip = Microphone.Start(_currentDevice != null ? _currentDevice : string.Empty, false, _maxRecordingLength, _sampleRate); - - Debug.Log($"[AudioRecorder] 음성 녹음 시작됨 (최대 {_maxRecordingLength}초, {_sampleRate}Hz)"); - OnRecordingStarted?.Invoke(); - - return true; + _isRecording = true; + _recordingStartTime = Time.time; + + _recordingClip = Microphone.Start(_currentDevice ?? string.Empty, false, _maxRecordingLength, _sampleRate); + if (_recordingClip == null) + { + _isRecording = false; + Debug.LogError("[AudioRecorder] 마이크 시작 실패: 반환된 AudioClip이 null입니다."); + OnError?.Invoke("마이크 시작 실패"); + return false; + } + + Debug.Log($"[AudioRecorder] 음성 녹음 시작됨 (최대 {_maxRecordingLength}초, {_sampleRate}Hz)"); + OnRecordingStarted?.Invoke(); + return true;
149-158: 예외 경로에서도 항상OnRecordingStopped를 보장하세요.현재
catch경로에서는OnRecordingStopped가 호출되지 않아 구독자가 정리 로직을 받지 못할 수 있습니다.finally에서 한 번만 보장 호출하는 형태로 통합하세요.권장(diff):
- OnRecordingStopped?.Invoke(); - return null; - } - catch (Exception ex) - { - Debug.LogError($"[AudioRecorder] 녹음 중지 실패: {ex.Message}"); - OnError?.Invoke($"녹음 중지 실패: {ex.Message}"); - _isRecording = false; - return null; - } + OnRecordingStopped?.Invoke(); + return null; + } + catch (Exception ex) + { + Debug.LogError($"[AudioRecorder] 녹음 중지 실패: {ex.Message}"); + OnError?.Invoke($"녹음 중지 실패: {ex.Message}"); + _isRecording = false; + return null; + } + finally + { + // 중복 호출 방지를 위해 성공 분기에서 이미 호출했다면 옵저버 측에서 idempotent 처리 가정 + OnRecordingStopped?.Invoke(); + }비고: 중복 호출이 우려되면
bool stoppedRaised플래그로 한 번만 호출되도록 정교화할 수 있습니다.Assets/Domain/Character/Script/Config/Live2DModelConfig.cs (1)
80-87: 용어 오타(lockAt → lookAt) 및 역호환 보장 리팩터
lockAtDamping은 시선 추적(LookAt) 컨텍스트상lookAtDamping이 맞습니다. 필드명을 수정하되, 에셋 값 보존을 위해FormerlySerializedAs로 역호환을 보장하고, 속성은 신규/구명 병행 노출 후 구명에[Obsolete]를 권장합니다.+ using UnityEngine.Serialization; // 파일 상단 using 추가 @@ - [SerializeField] private float lockAtDamping = 0.0f; + [SerializeField, FormerlySerializedAs("lockAtDamping")] + private float lookAtDamping = 0.0f; @@ - public float LockAtDamping => lockAtDamping; + [Obsolete("Use LookAtDamping instead.")] + public float LockAtDamping => lookAtDamping; + public float LookAtDamping => lookAtDamping;Also applies to: 155-159
Assets/Core/Managers/SystemManager.cs (1)
214-216: 씬 이름 오타로 인한 전환 실패 가능성: "MainSence" → "MainScene"현재 문자열
"MainSence"는 일반적으로 오타로 보입니다. 존재하지 않는 씬 이름이면 전환 시 런타임 오류가 납니다. 아래와 같이 교체를 권장합니다.- await UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("MainSence"); + await UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("MainScene");
♻️ Duplicate comments (4)
Assets/Domain/Character/Script/CharacterManager.cs.meta (1)
1-2: 위와 동일: .cs.meta에 MonoImporter 블록이 없습니다 — 명시적 추가 권장.CharacterManager는 실행 순서(Execution Order) 요구사항이 생길 수 있으므로, 기본값이라도 명시해 두면 변경/리뷰가 수월합니다. 첫 코멘트의 제안 패턴을 동일 적용해 주세요.
Assets/Domain/Character/Script/CharacterModelLoader.cs.meta (1)
1-2: 위와 동일: MonoImporter 섹션 누락.ModelLoader는 Import 설정 변경 가능성이 높은 스크립트입니다. 추후 변경 히스토리를 위해서라도 기본 블록을 포함시켜 두는 것을 권장합니다.
Assets/Domain/Character/Script/Component/ResolutionManager.cs.meta (1)
1-2: 위와 동일: MonoImporter 섹션 누락.Resolution 관련 컴포넌트는 에디터 간 충돌이 자주 납니다. Importer 블록을 고정해 두면 불필요한 diff를 줄일 수 있습니다.
Assets/Domain/Chat/Model/CostInfo.cs.meta (1)
1-2: 위와 동일: MonoImporter 섹션 누락.Chat/Cost 트래킹 로직은 협업이 잦은 영역이라 메타 안정화가 중요합니다. 기본 Importer 블록을 명시해 주세요.
🧹 Nitpick comments (59)
Assets/Domain/Chat/Model/CharacterActionData.cs.meta (1)
1-2: .cs.meta에서 MonoImporter 섹션이 누락되어 있습니다 — 기본값을 명시해 두는 편이 안전합니다.Unity가 자동으로 기본 Import 설정을 채워주긴 하지만, 팀/브랜치 간 병합 시 의도치 않은 재생성(diff churn)과 에디터별 편차를 줄이기 위해 MonoImporter 블록을 메타에 포함하는 것을 권장합니다.
아래처럼 기본 블록을 추가해 주세요(같은 패턴을 이번 PR의 모든 .cs.meta에 적용 권장).
fileFormatVersion: 2 guid: 333379fbd87c0304db4ae39689691795 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 0} + userData: + assetBundleName: + assetBundleVariant:Assets/Domain/Character/Script/Component/ResolutionManager.cs.meta (1)
1-2: 파일 말미 개행(Newline at EOF) 추가를 권장합니다.일부 도구/플러그인은 EOF 개행 유무로 불필요한 diff를 생성합니다. 한 줄 개행을 추가해 주세요.
Assets/Domain/Chat/Model/CostInfo.cs.meta (1)
1-2: EOF 개행이 없습니다 — 추가 권장.사소하지만 CI/리뷰 노이즈를 줄이는 데 도움이 됩니다.
Assets/Core/Audio/AudioRecorder.cs (2)
282-289: 실제 샘플 수는_recordingClip.frequency를 기반으로 계산하는 것이 더 견고합니다.디바이스가 요청한
_sampleRate를 그대로 지원하지 않을 수 있습니다. 실측 클립의frequency를 사용하면 왜곡 가능성을 줄일 수 있습니다.권장(diff):
- int actualSamples = Mathf.RoundToInt(actualDuration * _sampleRate); + int actualSamples = Mathf.RoundToInt(actualDuration * _recordingClip.frequency);
101-101: 널 병합 연산자로 간결화.
_currentDevice != null ? _currentDevice : string.Empty대신??사용으로 가독성을 개선하세요.권장(diff):
- _recordingClip = Microphone.Start(_currentDevice != null ? _currentDevice : string.Empty, false, _maxRecordingLength, _sampleRate); + _recordingClip = Microphone.Start(_currentDevice ?? string.Empty, false, _maxRecordingLength, _sampleRate);- Microphone.End(_currentDevice != null ? _currentDevice : string.Empty); + Microphone.End(_currentDevice ?? string.Empty);Also applies to: 135-135
Assets/Core/Audio/AudioManager.cs (3)
70-87: 구독 타이밍 레이스 대비: ‘이미 초기화된’ 경우도 처리하는 헬퍼 제공 제안Initialize 직후에만 이벤트가 발행되므로, 나중에 구독한 컴포넌트는 놓칠 수 있습니다. 다음과 같이 즉시 실행/지연 구독을 통합하는 유틸을 제공하면 사용성이 좋아집니다.
추가(파일 내 임의 위치, public 메서드로):
public void WhenInitialized(Action action) { if (action == null) return; if (_isInitialized) { action(); return; } OnInitialized += action; }사용 예:
AudioManager.Instance.WhenInitialized(() => { // 초기화 이후 안전한 접근 });
254-257: 내부 컨트롤러 직접 노출 최소화 및 API 단순화직접 게터 대신 읽기 전용 프로퍼티로 단순화하면 호출부 가독성과 캡슐화가 향상됩니다.
아래처럼 메서드를 프로퍼티로 교체하는 것을 권장합니다(호출 사이트 일괄 치환 필요: GetVoiceController() → VoiceController).
- public VoiceController? GetVoiceController() - { - return _voiceController; - } + public VoiceController? VoiceController => _voiceController;대안: 컨크리트 타입 노출을 줄이려면 IAudioController(또는 IReadOnlyVoiceController 같은 얇은 인터페이스)로 반환 타입을 한정해 결합도를 낮출 수 있습니다.
70-87: 검증 결과: 이름 일관성 문제 없음 & OnInitialized 이벤트 구독 여부 확인 필요
- _audio_manager, _audio_source, _is_playing 등 의심 식별자는 전체 코드베이스 스캔 결과 존재하지 않음 확인 (rg 스캔)
- OnInitialized 이벤트는
Assets/Core/Audio/AudioManager.cs내에서 선언 및 Invoke만 확인, 외부 구독자는 미발견됨필요하다면 ChatSystemManager, VoiceController 등 AudioManager 초기화 완료 알림을 받아야 하는 컴포넌트에서 OnInitialized 이벤트 구독을 추가하거나, 사용되지 않는다면 이벤트 제거를 고려해주세요.
Assets/Domain/Chat/View/TextInputView.cs (2)
40-43: SetChatManager 인자 유효성 검사 추가 제안null 전달 시 이후 호출에서 NRE가 발생할 수 있습니다. 간단한 가드를 추가해 방어적으로 처리하는 것을 권장합니다.
- public void SetChatManager(ChatSystemManager chatManager) - { - _chatManager = chatManager; - } + public void SetChatManager(ChatSystemManager chatManager) + { + if (chatManager == null) + { + Debug.LogError("[TextInputView] ChatSystemManager가 null입니다."); + return; + } + _chatManager = chatManager; + }
76-86: 인스턴스 획득 방식 단순화 및 경고 메시지 업데이트싱글턴을 제공하므로 Find 호출 대신 Instance 사용이 명확합니다. 또한 로그 메시지의 클래스명이 갱신되지 않았습니다.
- _chatManager = FindAnyObjectByType<ChatSystemManager>(); + _chatManager = ChatSystemManager.Instance; if (_chatManager == null) { - Debug.LogWarning("[TextInputView] ChatManager를 찾을 수 없습니다. 수동으로 SetChatManager를 호출해주세요."); + Debug.LogWarning("[TextInputView] ChatSystemManager를 찾을 수 없습니다. 수동으로 SetChatManager를 호출해주세요."); }Assets/Docs/ProjectVG_Structure_Guide.md (4)
31-38: 'Script' vs 'Scripts' 혼용 — 디렉터리명 일관화 제안Domain 계층에서는
Script/를, UI 계층에서는Scripts/를 사용하고 있어 혼용됩니다. 검색/탐색성과 신규 온보딩 가독성을 위해 복수형(Scripts/)으로 통일하는 것을 권장합니다.아래와 같이 트리 예시를 조정하는 패치 제안:
-│ │ ├── Script/ +│ │ ├── Scripts/ ... -│ │ ├── Script/ +│ │ ├── Scripts/Also applies to: 47-47
39-41: 트리 도식의 브랜치 기호 오타
Popup하위에서 자식 노드 두 개가 모두└──로 표기되어 있습니다. 첫 자식은├──, 마지막 자식만└──가 되어야 시각적으로 올바릅니다.-│ │ └── System/ # 팝업 매니저, 팝업 큐 -│ │ └── Instances/ # 실제 팝업 프리팹들 +│ │ ├── System/ # 팝업 매니저, 팝업 큐 +│ │ └── Instances/ # 실제 팝업 프리팹들
51-56: Resources 사용 경계 조건을 문서에 명시해주세요
Resources/는 런타임 상주 특성으로 메모리 압력을 높이므로, 대용량 에셋은 Addressables 우선,Resources에는 경량 설정/플레이스홀더만 권장 같은 한 줄 가이드를 추가하면 실무 적용 시 안전합니다. 또한AddressablesDummy/의 사용 시점(개발/테스트 한정)을 명시하면 더 명확합니다.
90-97: 관련 가이드에 하이퍼링크 추가 제안Live2D 활용 예시 아래에 이번 PR에 포함된
Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md를 교차 링크하면 독자가 흐름(Structure → Live2D 해상도 스케일링)으로 이어서 읽기 좋습니다.Assets/Core/Audio/NewAudioMixer.mixer (1)
65-65: Exposed Parameter 미설정 — 볼륨 제어 전략 확인 필요
m_ExposedParameters: []입니다. 코드에서AudioMixer.SetFloat("BGMVolume", ...)등으로 볼륨을 제어하려면 각 그룹의 Volume 파라미터를 Expose해야 합니다(그룹 선택 → Volume 우클릭 → Expose). 스냅샷 기반이 아니라 직접 제어라면 파라미터 노출을 추가해 주세요.Assets/Domain/Chat/Model/CostInfo.cs (2)
11-14: 비즈니스 의미 명확화(단위/명명) 검토
UsedCost,RemainingCost가 토큰 수를 의미한다면UsedTokens,RemainingTokens같은 명칭이 오해를 줄입니다. 금액(통화)이면 float는 반올림 오차가 있어 부적합하므로decimal을 검토해야 합니다. 현재 DTO(ChatResponse)가float?이므로 일단 정합성은 맞습니다.
26-29: 로그/표시 문자열의 문화권 독립 및 소수점 포맷 고정UI/로그 혼용 시 문화권에 따라 소수점/구분자가 달라질 수 있습니다. 불필요한 소수점 꼬리 방지를 위해 고정 포맷과 InvariantCulture를 권장합니다.
- return $"Used: {UsedCost} Token, Remaining: {RemainingCost} Token"; + using System.Globalization; // 파일 상단에 추가 + return string.Format( + CultureInfo.InvariantCulture, + "Used: {0:0.##} Tokens, Remaining: {1:0.##} Tokens", + UsedCost, RemainingCost);Assets/Domain/Character/Script/Config/Live2DModelConfig.cs (2)
151-153: ScriptableObject 외부 변형 방지(읽기 전용 인터페이스 노출)에디터/런타임에서
List<>참조가 그대로 노출되면 외부 코드가 에셋 내용을 변경할 수 있습니다. 프로퍼티 타입을IReadOnlyList<>로 노출하고 내부 목록만List<>로 유지하는 것을 권장합니다.- public List<EmotionMapping> EmotionMappings => emotionMappings; - public List<ActionMapping> ActionMappings => actionMappings; + public IReadOnlyList<EmotionMapping> EmotionMappings => emotionMappings; + public IReadOnlyList<ActionMapping> ActionMappings => actionMappings;
93-99: 기본값 및 범위 설정 합리적 — 연동 컴포넌트와의 계약만 명시되면 충분립싱크/오토 블링크 토글과 타이밍 파라미터 구성은 실무에서 쓰기 좋습니다. 추후
CharacterModelLoader에서 이 값들이 어떤 컴포넌트(CubismAudioMouthInput, CubismAutoEyeBlinkInput 등)에 어떻게 매핑되는지(단위/스케일)만 주석으로 합의해 두면 유지보수성이 더 좋아집니다.Also applies to: 104-137, 160-169
Assets/Domain/Character/Script/CharacterActionController.cs (3)
48-49: 불필요한 로그 제거
Debug.Log(actionType);는 상위 로깅(70라인)과 중복되어 콘솔 노이즈만 증가합니다. 제거를 권장합니다.- Debug.Log(actionType);
52-67: Animator 파라미터 문자열 의존 제거(해시 사용) 및 트리거 정리문자열 기반
SetTrigger/SetBool은 GC/성능 및 오타 리스크가 있습니다. 파라미터 해시를 캐싱하고, 정지 시 관련 트리거를ResetTrigger로 정리하면 안전합니다.+ private static readonly int HashIdle = Animator.StringToHash("Idle"); + private static readonly int HashListen = Animator.StringToHash("Listen"); + private static readonly int HashTalk = Animator.StringToHash("Talk"); @@ - _animator.SetTrigger("Idle"); - _animator.SetBool("Talk", false); + _animator.SetTrigger(HashIdle); + _animator.SetBool(HashTalk, false); @@ - _animator.SetTrigger("Listen"); - _animator.SetBool("Talk", false); + _animator.SetTrigger(HashListen); + _animator.SetBool(HashTalk, false); @@ - _animator.SetBool("Talk", true); + _animator.SetBool(HashTalk, true); @@ - _animator.SetTrigger("Idle"); - _animator.SetBool("Talk", false); + _animator.ResetTrigger(HashListen); + _animator.ResetTrigger(HashIdle); + _animator.SetTrigger(HashIdle); + _animator.SetBool(HashTalk, false);Also applies to: 86-87
36-43: Animator 파라미터 존재 여부 사전 검증 권장런타임에 미존재 파라미터를 호출하면 경고가 발생합니다.
Initialize시 한 번Animator.parameters를 검사해 누락된 파라미터를 로그로 명시하면 원인 추적이 쉬워집니다.예시:
public void Initialize(Animator animator) { _animator = animator; _isPlaying = false; _currentAction = CharacterActionType.Idle; + // 파라미터 사전 검증(옵션) + var names = new HashSet<string>(); + foreach (var p in _animator.parameters) names.Add(p.name); + if (!names.Contains("Idle") || !names.Contains("Listen") || !names.Contains("Talk")) + Debug.LogWarning("[CharacterActionController] Animator 파라미터(Idle/Listen/Talk) 누락 감지"); }Assets/Core/Managers/SystemManager.cs (2)
23-23: 미사용 직렬화 필드 정리 또는 실제 초기화에 통합 필요
_chatManager필드가 선언만 되어 있고 전역적으로 사용되지 않습니다. Inspector 노출만 하고 사용하지 않으면 유지보수 시 혼란을 줄 수 있습니다. 아래 중 하나를 권장합니다.
- 단순 제거
- 또는 매니저 생성/초기화 흐름에 통합해서 실제로 참조 사용
Option A — 제거:
-[SerializeField] private ChatSystemManager? _chatManager;Option B — 생성 로직에 통합(아래 CreateManagersIfNotExist 코멘트 참고) 후 사용 지점 추가.
228-238: ChatSystemManager 인스턴스 확보 누락다른 매니저들은
CreateManagersIfNotExist에서 인스턴스를 확보하지만ChatSystemManager는 누락되어 있습니다. 싱글톤 패턴과 일관성을 위해 함께 확보해 두는 것이 좋습니다.private void CreateManagersIfNotExist() { if (_createManagersIfNotExist) { _webSocketManager = WebSocketManager.Instance; _sessionManager = SessionManager.Instance; _httpApiClient = HttpApiClient.Instance; _audioManager = AudioManager.Instance; _loadingManager = LoadingManager.Instance; + _chatManager = ChatSystemManager.Instance; } }추가로 상태 로깅(
LogManagerStatus)에도 Chat 상태 출력이 있으면 디버깅에 유용합니다.Assets/Domain/Chat/View/VoiceInputView.cs (3)
240-247: 초기화 레이스 컨디션 방지: 초기화 완료 전 버튼 비활성화
FindAnyObjectByType<ChatSystemManager>()로 참조는 얻었지만, 내부적으로ChatSystemManager는InitializeWhenReady코루틴을 통해 지연 초기화됩니다. 초기화 완료 전 음성 전송을 시도하면 사용자 버블만 생성되고 실제 전송이 누락될 수 있습니다.권장:
ChatSystemManager.IsInitialized확인 전까지 음성 버튼 비활성화 또는 대기.예시:
private void SetupChatManager() { if (_chatManager == null) { _chatManager = FindAnyObjectByType<ChatSystemManager>(); if (_chatManager == null) { Debug.LogWarning("[VoiceInputView] ChatManager를 찾을 수 없습니다. 수동으로 SetChatManager를 호출해주세요."); + UpdateVoiceButtonState(false); + return; } } + + // 초기화 대기 코루틴 시작 + StartCoroutine(WaitUntilChatReady()); } + +private System.Collections.IEnumerator WaitUntilChatReady() +{ + while (_chatManager != null && !_chatManager.IsInitialized) + yield return null; + UpdateVoiceButtonState(true); +}
80-101: 전송 전 가드 추가: ChatSystemManager 준비 여부 확인
SendVoiceMessage에서_chatManager?.SendUserMessage를 호출하기 전에 매니저 존재 및 초기화 여부를 검사해 사용자에게 명확한 피드백을 주는 것이 좋습니다.- if (!string.IsNullOrWhiteSpace(transcribedText)) + if (!string.IsNullOrWhiteSpace(transcribedText)) { - _chatManager?.SendUserMessage(transcribedText); - OnVoiceMessageSent?.Invoke(transcribedText); + if (_chatManager == null) + { + OnError?.Invoke("ChatSystemManager를 찾을 수 없습니다."); + return; + } + if (!_chatManager.IsInitialized) + { + OnError?.Invoke("채팅 시스템이 아직 준비되지 않았습니다. 잠시 후 다시 시도해 주세요."); + return; + } + _chatManager.SendUserMessage(transcribedText); + OnVoiceMessageSent?.Invoke(transcribedText); }
126-127: 불필요한 상태값 제거로 간소화
_recordingStartTime은 더 이상 사용되지 않습니다(최대 시간 체크 로직 제거 주석과 일치). 상태 관리 단순화를 위해 할당 및 필드를 제거하는 것이 좋습니다.적용 예:
- private float _recordingStartTime; ... - _recordingStartTime = Time.time;Assets/Infrastructure/Network/DTOs/Chat/ChatResponse.cs (2)
23-25: Action을 문자열로 노출하기보다 강타입(enum) 또는 입력 검증을 고려해주세요서버가 "idle/listen/talk" 외의 문자열을 보낼 경우, 도메인 레이어까지 그대로 전파됩니다. 최소한 허용 값 화이트리스트 검증 또는 StringEnumConverter 기반 역직렬화를 권장합니다. 현재 PR에서는 CharacterActionData에서 파싱을 하고 있지만, DTO 단계에서 1차 방어를 해두면 디버깅과 유효성 보장이 쉬워집니다.
적용 예시(선호):
- [JsonProperty("action")] - public string? Action { get; set; } + [JsonProperty("action")] + public string? Action { get; set; } // 유지 + // TODO: DTO 수준에서 허용 문자열("idle","listen","talk") 외 입력 시 null 처리 또는 로그
35-40: 금액/크레딧 의미의 Cost를 float 대신 double/decimal로 저장하는 것을 권장float는 표현 정밀도가 낮아 누적 오차가 발생하기 쉽습니다. 비용/잔액 성격이라면 double(성능 우선) 또는 decimal(금융/정밀 우선)로 변경을 검토해주세요. 또한 서버에서 0 또는 음수(정책상 불가) 케이스가 들어올 때의 해석(절삭/절대값/무시)도 명확히 해두면 좋습니다.
Assets/Domain/Chat/Model/CharacterActionData.cs (4)
48-54: 문자열 소문자 변환은 ToLowerInvariant() 사용 권장문화권에 따른 소문자 규칙 차이를 피하기 위해 ToLower() 대신 ToLowerInvariant() 사용이 안전합니다.
- return actionString.ToLower() switch + return actionString.ToLowerInvariant() switch { "idle" => CharacterActionType.Idle, "listen" => CharacterActionType.Listen, "talk" => CharacterActionType.Talk, _ => CharacterActionType.Idle };
2-4: 레이어 결합도 완화: Chat 모델이 Character.Service 네임스페이스에 의존Chat 도메인 모델이 CharacterActionType(현재 CharacterActionController.cs에 정의)에 직접 의존합니다. enum을 공용 도메인(예: ProjectVG.Domain.Shared 또는 ProjectVG.Domain.Character.Abstractions)으로 분리하면 계층 간 결합도를 낮출 수 있습니다.
1-1: 불필요한 using 정리UnityEngine 네임스페이스를 사용하지 않습니다. 불필요한 의존성 제거를 권장합니다.
-using UnityEngine;
43-47: 기본값/비정상 값의 정책 합리화 제안null/empty는 Talk, 미인식 문자열은 Idle로 매핑됩니다. 둘 모두 동일 기본값(예: Idle 또는 Talk)으로 통일하거나, 미인식 입력을 로그로 남기고 Idle로 폴백하는 등 정책을 명문화하면 유지보수성이 좋아집니다.
Assets/Domain/Chat/Model/ChatMessage.cs (3)
27-31: 오디오 Base64 파싱 실패 시 방어 코드 권장외부 입력이므로 FromBase64에서 예외가 발생할 수 있습니다. 실패 시 로그만 남기고 텍스트 메시지 처리는 계속되도록 try/catch를 권장합니다.
- if (!string.IsNullOrEmpty(response.AudioData)) - { - chatMessage.VoiceData = VoiceData.FromBase64(response.AudioData, response.AudioFormat); - } + if (!string.IsNullOrEmpty(response.AudioData)) + { + try + { + chatMessage.VoiceData = VoiceData.FromBase64(response.AudioData, response.AudioFormat); + } + catch (Exception ex) + { + Debug.LogWarning($"[ChatMessage] 오디오 데이터 파싱 실패: {ex.Message}"); + } + }
44-46: HasActionData 논리 재점검 필요CharacterActionData.HasAction() 수정(항상 true → 명시 여부 반영)에 맞춰, 현재 구현은 그대로 사용해도 됩니다. 다만 ActionData를 생성 시점 조건부로 바꾸면(위 제안) 이 메서드는
ActionData != null만으로 충분해집니다.- public bool HasActionData() => ActionData != null && ActionData.HasAction(); + public bool HasActionData() => ActionData != null;
32-35: CostInfo 조건 생성 로직은 합리적이나, 0 값도 의미 있는 경우가 있는지 확인현재는 0/0이면 생성하지 않습니다. “잔여 크레딧만 의미 있음(사용 0)” 또는 “정확한 사용량을 UI에 항상 표시” 같은 요구가 있다면, 생성 조건을 ‘null 여부’로 바꾸는 옵션도 검토해주세요.
Assets/Domain/Character/Script/CharacterModelLoader.cs (3)
30-34: Initialize 인자 유효성 확인 및 NRT 명시 권장modelRegistry가 null일 수 있는 경로가 있다면 조기에 방어하세요. 또한 본 파일은 NRT가 꺼져 있어 메서드 시그니처만으로 null 허용 여부가 드러나지 않습니다.
#nullable enable도입 또는 파라미터에?표시를 권장합니다.- public void Initialize(Live2DModelRegistry modelRegistry, AudioSource voiceAudioSource) + public void Initialize(Live2DModelRegistry modelRegistry, AudioSource voiceAudioSource) { - _modelRegistry = modelRegistry; + if (modelRegistry == null) + { + Debug.LogError("[CharacterModelLoader] Live2DModelRegistry가 null입니다."); + return; + } + _modelRegistry = modelRegistry; _voiceAudioSource = voiceAudioSource; }
72-88: null 반환 가능성이 있는 메서드의 반환 형식 명시설정 누락 시
return null이 여러 곳에 존재합니다. API 명확성을 위해UniTask<GameObject?>로 바꾸거나, 예외/Result 패턴으로 의도를 드러내는 것을 권장합니다. 현재 사용처(CharacterManager 등)에서 null 처리가 가능한지 확인 필요합니다.
126-135: 매직 스트링 상수화 제안: "ParamMouthOpenY"파라미터 ID는 오타·변경 리스크가 큽니다. 상수로 추출해 재사용하면 유지보수에 유리합니다.
Assets/Domain/Character/Script/Component/ResolutionManager.cs (3)
81-88: FindObjectsOfType에서 비활성(Disabled) 오브젝트 포함 여부 확인현재는 활성 오브젝트만 수집됩니다. 비활성 모델도 초기 스케일 적용 대상이라면 includeInactive 지원 버전(Unity 2020.2+)에서는
FindObjectsOfType<Live2DModelScaler>(true)를, 그 이전 버전이면 적절한 대안(Resources.FindObjectsOfTypeAll + 필터)을 사용하세요.- var scalers = FindObjectsOfType<Live2DModelScaler>(); + var scalers = FindObjectsOfType<Live2DModelScaler>(true); // Unity 2020.2+인 경우
142-153: 신규 등록 스케일러에 즉시 스케일 적용 고려등록 직후 다음 해상도 변경까지 기다리지 않고 현재 스케일을 바로 적용하면 일관된 UX를 만들 수 있습니다.
if (scaler != null && !modelScalers.Contains(scaler)) { modelScalers.Add(scaler); + if (scaleConfig != null) + { + var scale = scaleConfig.CalculateScale(); + scaler.ApplyScaleWithPreCalculatedScale(scale); + }
189-193: 해상도 변경 감지 시 Vector2 대신 정수 비교 또는 Vector2Int 사용 권장현재 Vector2로 저장하고 비교하지만, 해상도는 정수 개념입니다.
Vector2Int또는 width/height 정수 비교가 더 명확합니다.- var currentResolution = new Vector2(Screen.width, Screen.height); - return currentResolution != lastResolution; + var currentResolution = new Vector2(Screen.width, Screen.height); + return currentResolution != lastResolution; // 기능은 동일하나 Vector2Int 사용을 고려Assets/Domain/Chat/Service/ChatMessageQueue.cs (3)
20-23: Count/IsEmpty는 현재 락 없이 읽혀 비일관 상태를 노출할 수 있음
Enqueue/Dequeue/Clear는 락으로 보호되지만,Count/IsEmpty는 락 없이 읽혀 경쟁 상황에서 잘못된 값을 반환할 수 있습니다.GetStatus()가 이미 스냅샷을 안전하게 제공하므로, 두 프로퍼티도 락으로 보호하거나 외부에는GetStatus()만 노출하는 것을 권장합니다.다음과 같이 최소 수정 가능합니다:
- public int Count => _messageQueue.Count; - public bool IsProcessing => _isProcessing; - public bool IsEmpty => _messageQueue.Count == 0; + public int Count { get { lock (_queueLock) { return _messageQueue.Count; } } } + public bool IsProcessing { get { lock (_queueLock) { return _isProcessing; } } } + public bool IsEmpty { get { lock (_queueLock) { return _messageQueue.Count == 0; } } }
42-49: 큐 가득 참 시에도 콜백으로 신호를 주십시오현재는 경고 로그만 출력하고
false를 반환합니다. 상위(예: UI/매니저)가 대응할 수 있도록OnError를 함께 호출하는 것이 좋습니다.if (_messageQueue.Count >= _maxQueueSize) { Debug.LogWarning($"[ChatMessageQueue] 메시지 큐가 가득 찼습니다. (최대: {_maxQueueSize})"); - return false; + OnError?.Invoke($"메시지 큐가 가득 찼습니다. (최대: {_maxQueueSize})"); + return false; }
80-112: UniTaskVoid 남용 및 취소 불가 처리 — 취소 토큰을 받아 propagate 하거나 UniTask로 전환 권장
UniTaskVoid는 예외 전파/취소가 어렵습니다. 큐 처리 중 객체 파괴/씬 전환 시 안전하게 중단하려면CancellationToken을 받아 내부await에 전달하거나 반환 형식을UniTask로 바꾸고 호출부에서.Forget()을 명시적으로 사용하는 구조가 좋습니다.필요 시 아래와 같이 선택적으로 개선할 수 있습니다(호출부 동반 변경 필요):
- public async UniTaskVoid ProcessQueueAsync(Func<ChatMessage, UniTask> processAction) + public async UniTask ProcessQueueAsync(Func<ChatMessage, UniTask> processAction, CancellationToken cancellationToken = default) { lock (_queueLock) { if (_isProcessing) return; _isProcessing = true; } try { - while (true) { + while (!cancellationToken.IsCancellationRequested) { ChatMessage? message = Dequeue(); if (message == null) { break; } try { - await processAction(message); + await processAction(message).AttachExternalCancellation(cancellationToken); OnMessageProcessed?.Invoke(message);Assets/Domain/Character/Script/Component/Live2DModelScaler.cs (3)
75-80: 사전 계산 스케일 적용 경로에서 scaleConfig null 시 조기 반환은 과도함
ApplyScaleWithPreCalculatedScale(float scale)는 이미 외부에서 계산된 스케일을 적용하는 목적이므로,scaleConfig == null이어도 적용 가능해야 합니다. 현재는 경고 후return하여 적용 자체가 막힙니다. 로그만 남기고 적용은 계속하도록 변경하세요.public void ApplyScaleWithPreCalculatedScale(float scale) { if (scaleConfig == null) { Debug.LogWarning("[Live2DModelScaler] 스케일 설정이 없습니다."); - return; + // 정보 로그만 남기고 적용은 계속 진행 }
134-148: 수동 스케일 범위 검증 누락음수/비정상 스케일이 적용될 수 있습니다. 최소 0 이상으로 클램프하거나
scaleConfig의 Min/Max를 고려하세요.public void SetManualScale(float scale) { if (originalScale == Vector3.zero) { originalScale = transform.localScale; + _originalScaleCaptured = true; } - - currentScale = scale; + currentScale = Mathf.Max(0f, scale); transform.localScale = originalScale * scale;
42-48: ResolutionManager와 중복 적용 가능성 — 역할 분담 정리 필요Update에서 해상도 변화를 감지해 자체 적용하고, 동시에
ResolutionManager도 주기적으로 전체 적용을 수행합니다. 중복 적용/중복 로그가 발생할 수 있으니, 매니저 사용 시 이 컴포넌트의applyOnResolutionChange를 끄거나, 매니저 존재 시 자체 적용을 생략하는 가드가 필요합니다.Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md (1)
29-31: 코드 펜스 언어 지정 누락(MD040) — lint 경고 해결이 블록은 언어 지정이 없어 markdownlint에 걸립니다.
text언어로 명시하세요.- ``` + ```text Assets > Create > ProjectVG > Character > Resolution Model Scale Config ```Assets/Domain/Chat/Service/ChatSystemManager.cs (3)
189-195: 디버그 잔존 로그 정리
Debug.Log(_chracterManager);/Debug.Log(chatMessage.ActionData);는 노이즈만 유발합니다. 필요 시 조건부 로그로 전환하거나 제거하세요.- Debug.Log(_chracterManager); // 캐릭터 액션 실행 - if (_chracterManager != null) + if (_characterManager != null) { - Debug.Log(chatMessage.ActionData); - _chracterManager.PlayAction(chatMessage.ActionData); + _characterManager.PlayAction(chatMessage.ActionData); }
76-82: UI 패널 미탐 시 완전 미초기화 — 기능 최소화 초기화로 degrade 권장5초 타임아웃 후
yield break로 종료하면 WebSocket 구독/큐 초기화도 이뤄지지 않습니다. UI 없이도 동작 가능한 범위(네트워크 수신/큐/오디오 등)는 초기화하도록 변경하는 것을 권장합니다.if (_chatBubblePanel == null) { Debug.LogError("[ChatSystemManager] ChatBubblePanel 초기화 타임아웃"); - yield break; + // UI 없이도 가능한 초기화는 시도 + Initialize(); + yield break; }
120-145: UX: 사용자 말풍선은 전송 즉시 표시하는 편이 자연스러움현재는 API 응답 전송 이후에 사용자 버블을 생성합니다. 네트워크 지연이 있을 때 UX가 어색합니다. 버블을 먼저 그리고, 실패 시 에러 표시만 별도로 처리하는 흐름을 권장합니다.
public async void SendUserMessage(string message) { if (!ValidateUserInput(message)) { return; } try { + if (_chatBubblePanel != null) { + _chatBubblePanel.CreateBubble(Actor.User, message); + } // 유저 메시지 전송 시 캐릭터를 Listen 상태로 변경 - if (_chracterManager != null) + if (_characterManager != null) { var listenAction = new CharacterActionData(CharacterActionType.Listen); - _chracterManager.PlayAction(listenAction); + _characterManager.PlayAction(listenAction); } if (_chatApiService != null) { var response = await _chatApiService.SendChatAsync( message: message, characterId: _characterId, userId: _userId ); if (response == null) { Debug.LogWarning("[ChatSystemManager] 채팅 응답이 null입니다."); } } - if (_chatBubblePanel != null) { - _chatBubblePanel.CreateBubble(Actor.User, message); - }Assets/Domain/Character/Script/Component/CameraResolutionScaler.cs (2)
181-196: 불필요한 계산 제거 및 주석 보완
baseAspect는 사용되지 않습니다. 제거해 코드 명료성을 높이세요.- var currentAspect = resolution.x / resolution.y; - var baseAspect = baseResolution.x / baseResolution.y; + var currentAspect = resolution.x / resolution.y;또한 이 방식은 세로/가로에 따라 높이/너비 중 하나만 정규화합니다.
ResolutionModelScaleConfig의 스케일과 곱할 때 중복 보정이 될 수 있으므로, 설계 의도(이중 보정인지, 보조 계수인지)를 주석으로 명확히 남기는 것을 권장합니다.
152-176: 스케일 합성 로직의 의도 확인(중복 보정 위험)카메라 스케일 = “해상도 비율 × Config 스케일”로 계산합니다.
ResolutionModelScaleConfig.CalculateScale()자체가 이미 해상도 기반 스케일이라면 이중 보정 가능성이 있습니다. 의도대로라면 둘 중 하나를 선택/가중하는 파라미터가 필요합니다(예:useConfigOnly,blendFactor).구현 의도를 문서/설정으로 확인해 주시고, 필요 시 파라미터 추가를 제안드립니다.
Assets/Domain/Character/Script/CharacterManager.cs (3)
48-54: 스케일러 자동 부착: _modelTransform이 null인 경우 커버리지 부족
_modelTransform이 미설정이면 스케일러가 전혀 부착되지 않습니다. 프리팹 루트(실제 인스턴스)에 스케일러가 없으면 로딩 완료 시점에 부착하는 보완 로직을 권장합니다.원하시면 로딩 완료 시
_currentCharacter에Live2DModelScaler존재 여부를 점검하고, 없을 경우 자동 부착하는 패치를 제안드릴게요.
145-164: AudioManager 초기화 타이밍 이슈 — Voice AudioSource 재획득/재바인딩 필요
GetVoiceAudioSource()는 초기화 시점에만 1회 조회합니다. 오디오 매니저가 늦게 초기화되는 경우 입모양(LipSync)에 오디오 입력이 영구히 누락될 수 있습니다. AudioManager의 초기화 완료 이벤트(요약에 따르면OnInitialized존재)를 구독하여 재획득/재바인딩하는 로직을 추가하는 것을 권장합니다.AudioManager에
OnInitialized이벤트가 맞는지 확인 부탁드립니다. 존재한다면 다음과 같은 형태로 보완 가능합니다:// Initialize 내 if (AudioManager.Instance != null) { AudioManager.Instance.OnInitialized += () => { var source = GetVoiceAudioSource(); _modelLoader.Initialize(_modelRegistry, source); // 필요 시 현재 모델의 mouth input에도 재바인딩 }; }
20-21: 이름 일관성: Service → Controller필드명
_currentActionService는 타입CharacterActionController와 불일치합니다._currentActionController로 변경하면 가독성이 향상됩니다.- private CharacterActionController _currentActionService; + private CharacterActionController _currentActionController;참고: 해당 식별자의 모든 사용처도 함께 변경 필요.
Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs (2)
33-44: 빈번 호출 시 미미하지만 오버헤드 존재 — 캐시/지연평가 고려(선택)
CalculateScale()가 프레임마다 호출되는 구조라면Screen.width/height조회 및 내부 로직을 캐시하거나 변경 이벤트(해상도 변경/세이프 영역 변경) 기반으로 갱신하는 것이 유리합니다.원하시면
ResolutionManager에서 이벤트 구독 방식으로 스케일을 브로드캐스트하는 구조 제안 드릴게요.
204-220: 모바일 판정 휴리스틱 보강 제안(선택)세로모드+높이 1000px 기준만으로는 태블릿/세로 모니터(피벗) 환경을 오탐/미탐할 수 있습니다. DPI, 안전영역, 짧은 변 길이(예: min(width,height) < 임계값) 등을 추가 고려하면 정확도를 높일 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (33)
Assets/App/Scenes/MainSence.unityis excluded by!**/*.unityAssets/Domain/Character/Model/Chikuwa/Character-Zero.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Model.fadeMotionList.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natoriConfig.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_Sample.prefabis excluded by!**/*.prefabAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Angry.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Blushing.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Normal.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Sad.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Smile.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/Surprised.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/exp_01.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/exp_02.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/exp_03.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/exp_04.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/exp/exp_05.exp3.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_00.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_01.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_02.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_03.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_04.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_05.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_06.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/motions/mtn_07.fade.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/natori_pro_t06.4096/texture_00.pngis excluded by!**/*.pngAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/natori_pro_t06.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/natori_pro_t06.prefabis excluded by!**/*.prefabAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/natori_pro_t06MaskTexture.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/runtime.expressionList.assetis excluded by!**/*.assetAssets/Domain/Character/Model/Sample/natori_pro_en/runtime/runtime.fadeMotionList.assetis excluded by!**/*.assetAssets/Resources/Character/Model/CharacterZero.assetis excluded by!**/*.assetAssets/Resources/Live2DModelRegistry.assetis excluded by!**/*.assetAssets/Resources/ResolutionModelScaleConfig.assetis excluded by!**/*.asset
📒 Files selected for processing (81)
.gitignore(1 hunks)Assets/Core/Audio/AudioManager.cs(3 hunks)Assets/Core/Audio/AudioRecorder.cs(1 hunks)Assets/Core/Audio/NewAudioMixer.mixer(4 hunks)Assets/Core/Managers/SystemManager.cs(1 hunks)Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md(1 hunks)Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md.meta(1 hunks)Assets/Docs/ProjectVG_Structure_Guide.md(1 hunks)Assets/Docs/ProjectVG_Structure_Guide.md.meta(1 hunks)Assets/Domain/Character/Model/Chikuwa.meta(1 hunks)Assets/Domain/Character/Model/Chikuwa/Character-Zero.asset.meta(1 hunks)Assets/Domain/Character/Model/Chikuwa/model.meta(1 hunks)Assets/Domain/Character/Model/Model.fadeMotionList.asset.meta(1 hunks)Assets/Domain/Character/Model/Sample.meta(1 hunks)Assets/Domain/Character/Script/CharacterActionController.cs(1 hunks)Assets/Domain/Character/Script/CharacterActionController.cs.meta(1 hunks)Assets/Domain/Character/Script/CharacterManager.cs(1 hunks)Assets/Domain/Character/Script/CharacterManager.cs.meta(1 hunks)Assets/Domain/Character/Script/CharacterModelLoader.cs(1 hunks)Assets/Domain/Character/Script/CharacterModelLoader.cs.meta(1 hunks)Assets/Domain/Character/Script/Component/CameraResolutionScaler.cs(1 hunks)Assets/Domain/Character/Script/Component/CameraResolutionScaler.cs.meta(1 hunks)Assets/Domain/Character/Script/Component/CubismHitHandler.cs(0 hunks)Assets/Domain/Character/Script/Component/CubismHitHandler.cs.meta(0 hunks)Assets/Domain/Character/Script/Component/CubismLookTarget.cs(0 hunks)Assets/Domain/Character/Script/Component/CubismLookTarget.cs.meta(0 hunks)Assets/Domain/Character/Script/Component/Live2DModelScaler.cs(1 hunks)Assets/Domain/Character/Script/Component/Live2DModelScaler.cs.meta(1 hunks)Assets/Domain/Character/Script/Component/ResolutionManager.cs(1 hunks)Assets/Domain/Character/Script/Component/ResolutionManager.cs.meta(1 hunks)Assets/Domain/Character/Script/Config/Live2DModelConfig.cs(3 hunks)Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs(1 hunks)Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs.meta(1 hunks)Assets/Domain/Character/Script/Controller/ActionController.cs(0 hunks)Assets/Domain/Character/Script/Controller/ActionController.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/DTOs.cs(0 hunks)Assets/Domain/Character/Script/Controller/DTOs.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/EmotionController.cs(0 hunks)Assets/Domain/Character/Script/Controller/EmotionController.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/IActionController.cs(0 hunks)Assets/Domain/Character/Script/Controller/IActionController.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/IEmotionController.cs(0 hunks)Assets/Domain/Character/Script/Controller/IEmotionController.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/ILive2DModelApplier.cs(0 hunks)Assets/Domain/Character/Script/Controller/ILive2DModelApplier.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/Live2DModelApplier.cs(0 hunks)Assets/Domain/Character/Script/Controller/Live2DModelApplier.cs.meta(0 hunks)Assets/Domain/Character/Script/Controller/Live2DParameterController.cs(0 hunks)Assets/Domain/Character/Script/Controller/Live2DParameterController.cs.meta(0 hunks)Assets/Domain/Character/Script/Manager/ILive2DCharacterManager.cs(0 hunks)Assets/Domain/Character/Script/Manager/ILive2DCharacterManager.cs.meta(0 hunks)Assets/Domain/Character/Script/Manager/Live2DCharacterManager.cs(0 hunks)Assets/Domain/Character/Script/Manager/Live2DCharacterManager.cs.meta(0 hunks)Assets/Domain/Character/Script/Manager/Live2DModelManager.cs(0 hunks)Assets/Domain/Character/Script/Manager/Live2DModelManager.cs.meta(0 hunks)Assets/Domain/Character/Script/Test/Live2DModelTest.cs(0 hunks)Assets/Domain/Character/Script/Test/Live2DModelTest.cs.meta(0 hunks)Assets/Domain/Character/Script/Test/TestVoice.cs(0 hunks)Assets/Domain/Character/Script/Test/TestVoice.cs.meta(0 hunks)Assets/Domain/Chat/Model/Actor.cs(1 hunks)Assets/Domain/Chat/Model/CharacterActionData.cs(1 hunks)Assets/Domain/Chat/Model/CharacterActionData.cs.meta(1 hunks)Assets/Domain/Chat/Model/ChatMessage.cs(1 hunks)Assets/Domain/Chat/Model/CostInfo.cs(1 hunks)Assets/Domain/Chat/Model/CostInfo.cs.meta(1 hunks)Assets/Domain/Chat/Model/VoiceData.cs(0 hunks)Assets/Domain/Chat/Service/ChatManager.cs(0 hunks)Assets/Domain/Chat/Service/ChatMessageQueue.cs(1 hunks)Assets/Domain/Chat/Service/ChatMessageQueue.cs.meta(1 hunks)Assets/Domain/Chat/Service/ChatSystemManager.cs(1 hunks)Assets/Domain/Chat/View/TextInputView.cs(3 hunks)Assets/Domain/Chat/View/VoiceInputView.cs(3 hunks)Assets/Infrastructure/Network/DTOs/Chat/ChatResponse.cs(2 hunks)Assets/Resources/Character/Model.meta(0 hunks)Assets/Resources/ResolutionModelScaleConfig.asset.meta(1 hunks)Assets/Samples.meta(0 hunks)Assets/Samples/Core.meta(0 hunks)Assets/Samples/Core/Managers.meta(0 hunks)Assets/Samples/Core/Managers/SampleSystemManager.cs(0 hunks)Assets/Samples/Core/Managers/SampleSystemManager.cs.meta(0 hunks)Assets/Voice.mixer(0 hunks)
💤 Files with no reviewable changes (39)
- Assets/Domain/Character/Script/Controller/IActionController.cs
- Assets/Samples.meta
- Assets/Samples/Core/Managers/SampleSystemManager.cs
- Assets/Resources/Character/Model.meta
- Assets/Domain/Character/Script/Controller/Live2DParameterController.cs.meta
- Assets/Samples/Core.meta
- Assets/Domain/Character/Script/Component/CubismHitHandler.cs
- Assets/Domain/Character/Script/Test/Live2DModelTest.cs.meta
- Assets/Domain/Character/Script/Component/CubismLookTarget.cs.meta
- Assets/Domain/Character/Script/Controller/Live2DModelApplier.cs
- Assets/Domain/Character/Script/Manager/Live2DModelManager.cs.meta
- Assets/Domain/Character/Script/Controller/Live2DModelApplier.cs.meta
- Assets/Domain/Character/Script/Controller/Live2DParameterController.cs
- Assets/Domain/Character/Script/Controller/ActionController.cs.meta
- Assets/Domain/Character/Script/Controller/DTOs.cs
- Assets/Domain/Chat/Model/VoiceData.cs
- Assets/Domain/Character/Script/Controller/EmotionController.cs
- Assets/Voice.mixer
- Assets/Domain/Character/Script/Manager/Live2DCharacterManager.cs
- Assets/Domain/Character/Script/Component/CubismHitHandler.cs.meta
- Assets/Domain/Character/Script/Manager/ILive2DCharacterManager.cs.meta
- Assets/Samples/Core/Managers.meta
- Assets/Domain/Character/Script/Manager/ILive2DCharacterManager.cs
- Assets/Domain/Character/Script/Controller/IActionController.cs.meta
- Assets/Samples/Core/Managers/SampleSystemManager.cs.meta
- Assets/Domain/Character/Script/Manager/Live2DCharacterManager.cs.meta
- Assets/Domain/Character/Script/Test/Live2DModelTest.cs
- Assets/Domain/Character/Script/Controller/EmotionController.cs.meta
- Assets/Domain/Character/Script/Test/TestVoice.cs
- Assets/Domain/Character/Script/Controller/ILive2DModelApplier.cs
- Assets/Domain/Chat/Service/ChatManager.cs
- Assets/Domain/Character/Script/Controller/ActionController.cs
- Assets/Domain/Character/Script/Component/CubismLookTarget.cs
- Assets/Domain/Character/Script/Controller/IEmotionController.cs.meta
- Assets/Domain/Character/Script/Manager/Live2DModelManager.cs
- Assets/Domain/Character/Script/Controller/ILive2DModelApplier.cs.meta
- Assets/Domain/Character/Script/Controller/DTOs.cs.meta
- Assets/Domain/Character/Script/Test/TestVoice.cs.meta
- Assets/Domain/Character/Script/Controller/IEmotionController.cs
🧰 Additional context used
🧬 Code graph analysis (17)
Assets/Core/Managers/SystemManager.cs (1)
Assets/Domain/Chat/Service/ChatSystemManager.cs (1)
ChatSystemManager(20-252)
Assets/Core/Audio/AudioManager.cs (1)
Assets/Core/Audio/VoiceController.cs (1)
VoiceController(10-216)
Assets/Domain/Character/Script/CharacterManager.cs (4)
Assets/Domain/Character/Script/CharacterModelLoader.cs (2)
CharacterModelLoader(15-184)Initialize(30-34)Assets/Domain/Character/Script/CharacterActionController.cs (5)
CharacterActionController(15-110)Initialize(25-30)PlayAction(36-77)StopCurrentAction(82-91)IsPlaying(97-100)Assets/Domain/Chat/Model/CharacterActionData.cs (4)
CharacterActionData(7-56)CharacterActionData(18-21)CharacterActionData(27-30)HasAction(36-36)Assets/Core/Audio/AudioManager.cs (1)
AudioManager(11-341)
Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs (1)
Assets/Domain/Character/Script/Component/ResolutionManager.cs (1)
ResolutionModelScaleConfig(169-172)
Assets/Domain/Chat/Model/CharacterActionData.cs (1)
Assets/Domain/Character/Script/CharacterActionController.cs (1)
CharacterActionType(106-109)
Assets/Domain/Chat/View/VoiceInputView.cs (2)
Assets/Domain/Chat/Service/ChatSystemManager.cs (1)
ChatSystemManager(20-252)Assets/Domain/Chat/View/TextInputView.cs (1)
SetChatManager(40-43)
Assets/Domain/Chat/Model/ChatMessage.cs (2)
Assets/Domain/Chat/Model/CharacterActionData.cs (4)
CharacterActionData(7-56)CharacterActionData(18-21)CharacterActionData(27-30)HasAction(36-36)Assets/Domain/Chat/Model/CostInfo.cs (3)
CostInfo(15-15)CostInfo(17-21)HasCostInfo(23-23)
Assets/Domain/Character/Script/CharacterActionController.cs (2)
Assets/Domain/Chat/Model/CharacterActionData.cs (1)
CharacterActionType(43-55)Assets/Domain/Character/Script/CharacterManager.cs (3)
Initialize(32-55)PlayAction(102-110)StopCurrentAction(115-118)
Assets/Domain/Character/Script/CharacterModelLoader.cs (3)
Assets/Domain/Character/Script/CharacterManager.cs (2)
AudioSource(145-164)Initialize(32-55)Assets/Domain/Character/Script/CharacterActionController.cs (2)
Initialize(25-30)CharacterActionController(15-110)Assets/Domain/Character/Script/Config/Live2DModelRegistry.cs (1)
TryGetConfig(18-30)
Assets/Domain/Chat/Service/ChatSystemManager.cs (9)
Assets/Domain/Chat/View/ChatBubblePanel.cs (2)
ChatBubblePanel(11-252)CreateBubble(55-107)Assets/Domain/Character/Script/CharacterManager.cs (3)
CharacterManager(13-167)Initialize(32-55)PlayAction(102-110)Assets/Infrastructure/Network/WebSocket/WebSocketManager.cs (1)
WebSocketManager(14-472)Assets/Core/Audio/AudioManager.cs (1)
AudioManager(11-341)Assets/Domain/Chat/Service/ChatMessageQueue.cs (4)
ChatMessageQueue(13-129)ChatMessageQueue(27-30)ChatMessage(58-63)Enqueue(37-52)Assets/Infrastructure/Network/Services/ApiServiceManager.cs (1)
ApiServiceManager(9-53)Assets/Domain/Chat/Model/CharacterActionData.cs (4)
CharacterActionData(7-56)CharacterActionData(18-21)CharacterActionData(27-30)CharacterActionType(43-55)Assets/Domain/Chat/Model/ChatMessage.cs (1)
ChatMessage(18-38)Assets/Domain/Chat/Model/VoiceData.cs (3)
VoiceData(13-18)VoiceData(20-40)IsPlayable(191-191)
Assets/Domain/Character/Script/Component/Live2DModelScaler.cs (2)
Assets/Domain/Character/Script/Component/ResolutionManager.cs (4)
ResolutionModelScaleConfig(169-172)ResolutionManager(12-232)RegisterModelScaler(142-153)UnregisterModelScaler(158-164)Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs (1)
CalculateScale(32-44)
Assets/Core/Audio/AudioRecorder.cs (2)
Assets/Domain/Chat/Model/ChatMessage.cs (1)
AudioClip(48-48)Assets/Core/Audio/VoiceController.cs (1)
AudioClip(193-196)
Assets/Domain/Character/Script/Component/CameraResolutionScaler.cs (2)
Assets/Domain/Character/Script/Component/ResolutionManager.cs (1)
ResolutionModelScaleConfig(169-172)Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs (1)
CalculateScale(32-44)
Assets/Domain/Chat/Model/CostInfo.cs (2)
Assets/Domain/Chat/Model/ChatMessage.cs (2)
Serializable(8-50)HasCostInfo(46-46)Assets/Infrastructure/Network/DTOs/Chat/ChatResponse.cs (1)
Serializable(8-43)
Assets/Domain/Character/Script/Component/ResolutionManager.cs (2)
Assets/Domain/Character/Script/Component/Live2DModelScaler.cs (3)
Live2DModelScaler(9-237)ApplyScaleWithPreCalculatedScale(73-112)GetCurrentScale(153-156)Assets/Domain/Character/Script/Config/ResolutionModelScaleConfig.cs (2)
CalculateScale(32-44)ResolutionInfo(190-202)
Assets/Domain/Chat/View/TextInputView.cs (2)
Assets/Domain/Chat/Service/ChatSystemManager.cs (1)
ChatSystemManager(20-252)Assets/Domain/Chat/View/VoiceInputView.cs (1)
SetChatManager(75-78)
Assets/Domain/Chat/Service/ChatMessageQueue.cs (1)
Assets/Domain/Chat/Service/ChatSystemManager.cs (1)
UniTask(182-218)
🪛 markdownlint-cli2 (0.17.2)
Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md
10-10: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
| /Assets/Domain/Character/Model/Chikuwa/ziraitikuwa | ||
| /Assets/Domain/Character/Model/Chikuwa/model |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
디렉터리 무시 패턴을 명확히 하고 .gitkeep 예외를 추가하세요.
현재는 디렉터리 경로 뒤에 슬래시가 없어 파일명과 충돌 여지가 있습니다. 또한 해당 폴더를 완전히 무시하면 Git이 빈 폴더를 생성하지 않아 Unity에서 model.meta만 존재하고 실제 폴더가 없어질 수 있습니다. 빌드/에셋 탐색 시 폴더 부재로 흐름이 끊길 수 있으니, 디렉터리 패턴에 슬래시를 붙이고 .gitkeep 예외를 추가해 폴더를 보존하는 것을 권장합니다.
적용 제안(diff):
/Assets/Plugins/FiveMinuteChat
/Assets/Plugins/WebGLTemplates
-/Assets/Domain/Character/Model/Chikuwa/ziraitikuwa
-/Assets/Domain/Character/Model/Chikuwa/model
+/Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/
+/Assets/Domain/Character/Model/Chikuwa/model/
+!/Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/.gitkeep
+!/Assets/Domain/Character/Model/Chikuwa/model/.gitkeep추가 작업:
- 위 두 디렉터리에 빈
.gitkeep파일을 커밋해 폴더를 저장소에 유지하세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /Assets/Domain/Character/Model/Chikuwa/ziraitikuwa | |
| /Assets/Domain/Character/Model/Chikuwa/model | |
| /Assets/Plugins/FiveMinuteChat | |
| /Assets/Plugins/WebGLTemplates | |
| /Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/ | |
| /Assets/Domain/Character/Model/Chikuwa/model/ | |
| !/Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/.gitkeep | |
| !/Assets/Domain/Character/Model/Chikuwa/model/.gitkeep |
🤖 Prompt for AI Agents
In .gitignore around lines 122-123, the two entries target directories but lack
trailing slashes and thus can match files; update the patterns to include
trailing slashes (e.g. /Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/) and
add negation rules to allow .gitkeep files (e.g.
!/Assets/Domain/Character/Model/Chikuwa/ziraitikuwa/.gitkeep), and do the same
for the second path; then create and commit an empty .gitkeep in each directory
so Git preserves the folders.
| 1. **CharacterFacade 사용 시** | ||
| - 모델 스케일러가 자동으로 추가됨 | ||
| - 별도 설정 불필요 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
CharacterFacade 자동 적용 부분 사실 확인 필요
가이드에 CharacterFacade 사용 시 자동 추가된다고 되어 있으나, 코드베이스에 해당 파사드가 보이지 않습니다. 존재하지 않거나 비활성화된 기능이면 문서를 정정해야 합니다.
🏁 Script executed:
#!/bin/bash
# CharacterFacade 존재 여부 확인
fd -a --exclude node_modules --exclude Library --exclude Packages --exclude ProjectSettings 'CharacterFacade.*\.(cs|md|asmdef|meta)$'
rg -nP '\bCharacterFacade\b' -C2 --glob '!**/Library/**' --glob '!**/node_modules/**' AssetsLength of output: 595
CharacterFacade 기능 미존재 확인: 가이드 수정 필요
코드베이스 전반을 검색한 결과 CharacterFacade 관련 구현(.cs, .asmdef 등)이 존재하지 않으며, 문서에서 “CharacterFacade 사용 시 자동 적용”으로 안내된 기능을 찾을 수 없습니다. 따라서 해당 설명은 삭제하거나 실제 적용 가능한 대체 API/클래스명으로 수정해야 합니다.
수정 대상:
- 파일:
Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md - 라인: 52–55
제안하는 diff:
- 1. **CharacterFacade 사용 시**
- - 모델 스케일러가 자동으로 추가됨
- - 별도 설정 불필요
+ 1. **(해당 기능 구현 미지원)**
+ - 현재 `CharacterFacade` 관련 자동 스케일러 적용 기능은 제공되지 않습니다.
+ - 향후 지원 시점에 맞추어 이 가이드를 업데이트해주세요.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 1. **CharacterFacade 사용 시** | |
| - 모델 스케일러가 자동으로 추가됨 | |
| - 별도 설정 불필요 | |
| 1. **(해당 기능 구현 미지원)** | |
| - 현재 `CharacterFacade` 관련 자동 스케일러 적용 기능은 제공되지 않습니다. | |
| - 향후 지원 시점에 맞추어 이 가이드를 업데이트해주세요. |
🤖 Prompt for AI Agents
Assets/Docs/Guides/Live2D_Resolution_Scaling_Guide.md lines 52-55: the doc
claims "CharacterFacade 사용 시 모델 스케일러가 자동으로 추가됨" but no CharacterFacade
implementation exists in the repo; remove this incorrect section or replace it
with the correct API/class name that actually enables automatic scaler (search
the codebase for the actual entry point or component that adds the scaler and
use that name), update the text to either state that automatic scaler is not
available and must be added manually (and provide brief steps) or reference the
correct class/API, and run a repo-wide search to confirm the replacement is
present elsewhere before committing.
| @@ -1,5 +1,5 @@ | |||
| fileFormatVersion: 2 | |||
| guid: a07cad638f33a9e448551011b2f085bf | |||
| guid: 2fc0b961763d08c47b49035b4dfb295d | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
폴더 GUID 변경 영향 점검 및 폴더 보존.
폴더 GUID 변경은 일반적으로 큰 문제는 없지만, Addressables/툴링에서 폴더 GUID를 참조하는 경우가 드물게 있어 영향 점검이 필요합니다. 또한 .gitignore로 폴더 전체를 무시하면 폴더 자체가 저장소에 존재하지 않을 수 있으니, .gitkeep 예외로 폴더를 보존하세요(별도 코멘트 참고).
빠른 점검 스크립트:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== 폴더 GUID 직접 참조 여부(YAML 내) =="
rg -n --no-messages -g '!Library/**' -g '!Logs/**' '2fc0b961763d08c47b49035b4dfb295d' || echo "직접 참조 없음(일반적)"Length of output: 266
폴더 GUID 직접 참조 없음 확인, .gitkeep로 폴더 보존 필요
빠른 스크립트 검증 결과, GUID 2fc0b961763d08c47b49035b4dfb295d는 해당 폴더의 model.meta 파일 외에는 코드베이스 내에서 직접 참조되는 부분이 없습니다.
따라서 Addressables나 기타 툴링에서의 영향은 없음을 확인했습니다.
– 여전히 .gitignore에 폴더 단위를 무시할 경우 폴더 자체가 저장소에 남지 않으므로,
해당 빈 폴더(Assets/Domain/Character/Model/Chikuwa/)에 .gitkeep 파일을 추가하여 폴더를 유지해주세요.
🤖 Prompt for AI Agents
Assets/Domain/Character/Model/Chikuwa/model.meta (lines 2-2): the folder
contains only a model.meta with GUID 2fc0b961763d08c47b49035b4dfb295d and will
be removed from the repo if the folder is empty due to .gitignore rules; add a
.gitkeep file into Assets/Domain/Character/Model/Chikuwa/ (and commit it) to
ensure the empty folder is preserved in the repository, and verify .gitignore
does not exclude .gitkeep so the folder remains tracked.
| guid: b1083908ab87d904a95806ad80fc75eb | ||
| NativeFormatImporter: | ||
| externalObjects: {} | ||
| mainObjectFileID: 24100000 | ||
| mainObjectFileID: 11400000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
GUID 및 mainObjectFileID 변경: 참조/타입 일치 검증 필요
GUID 교체(→ b1083908ab87d904a95806ad80fc75eb)와 메인 오브젝트 fileID 변경(24100000 → 11400000)은 씬/프리팹에서 서브에셋 참조가 깨질 수 있는 고위험 변경입니다. 특히 YAML 참조는 {fileID, guid, type} 조합으로 링크되므로 기존 조합이 남아있는지 확인을 권장합니다.
변경 후 씬/프리팹에서 관련 애니메이션/페이드 리스트가 정상 재생되는지 수동 재현 테스트도 권장합니다.
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
OLD_GUID="3bf46f7daa3260847aa1b964ad2b01a7"
# 이전 GUID 사용 흔적 검색(참조 잔재 확인)
rg -nP -C2 "$OLD_GUID" -g '!Library/**' -- '*.unity' '*.prefab' '*.asset' || echo "OK: 이전 GUID 참조 없음"
# fileID-참조 흔적(문맥 기반) 확인: 이전 fileID 숫자 주변을 스캔
rg -nP -C2 '24100000' -g '!Library/**' -- '*.unity' '*.prefab' '*.asset' || echo "참고: 이전 fileID 직접 참조 미발견"Length of output: 625
다음과 같이 검색 범위와 파일 필터링을 수정하여 다시 한 번 이전 GUID 및 fileID 참조를 확인해 주세요.
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
OLD_GUID="3bf46f7daa3260847aa1b964ad2b01a7"
OLD_FILEID="24100000"
echo "=== 이전 GUID 참조 검색 (.unity, .prefab, .asset, .asset.meta) ==="
rg -nP -C2 "$OLD_GUID" \
-g '!Library/**' \
-g '*.unity' \
-g '*.prefab' \
-g '*.asset' \
-g '*.asset.meta' \
|| echo "OK: 이전 GUID 참조 없음"
echo "=== 이전 fileID 참조 검색 (.unity, .prefab, .asset) ==="
rg -nP -C2 "$OLD_FILEID" \
-g '!Library/**' \
-g '*.unity' \
-g '*.prefab' \
-g '*.asset' \
|| echo "참고: 이전 fileID 직접 참조 미발견"Length of output: 278148
다음 경로에서 guid: 3bf46f7daa3260847aa1b964ad2b01a7(이전 GUID) 참조가 발견되었습니다. 이 값을 새 GUID(b1083908ab87d904a95806ad80fc75eb)로 모두 교체하거나, Unity 에디터에서 에셋 재연결을 수행해 주세요.
- Assets/App/Scenes/MainSence.unity (줄 528)
→
OutputAudioMixerGroup: {fileID: 24300002, guid: 3bf46f7daa3260847aa1b964ad2b01a7, type: 2}
guid값을 새 GUID로 업데이트하거나, 에디터에서 해당 AudioMixerGroup을 다시 연결해야 합니다.
이 외에도 Prefab(.prefab)·Asset(.asset)·Meta(.asset.meta) 파일 전역에서 guid: 3bf46f7daa3260847aa1b964ad2b01a7를 검색하여 누락된 참조가 없는지 반드시 검증해 주세요. 또한, fileID 변경(24100000 → 11400000)으로 인해 연결이 깨진 서브애셋이 없는지 수동 재생 테스트를 추천드립니다.
🤖 Prompt for AI Agents
In Assets/Domain/Character/Model/Model.fadeMotionList.asset.meta around lines 2
to 5, the file's GUID was changed to b1083908ab87d904a95806ad80fc75eb but other
assets (notably Assets/App/Scenes/MainSence.unity line 528) still reference the
old guid 3bf46f7daa3260847aa1b964ad2b01a7; update all occurrences of the old
GUID to the new GUID (or reassign the asset in the Unity Editor) and verify any
fileID changes (24100000 → 11400000) haven't broken sub-asset links; search the
repo for guid: 3bf46f7daa3260847aa1b964ad2b01a7 and replace or reconnect each
reference, then open the scene/prefabs in Unity to re-link the AudioMixerGroup
or affected assets and run a manual playtest to confirm everything loads
correctly.
| void Start() | ||
| { | ||
| Initialize(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
비동기 호출 미대기(unobserved)로 예외 누락 가능 — Start에서 명시적으로 await 권장
Initialize() 내부에서 LoadCharacter("zero")를 호출하지만 await하지 않아, 로드 중 발생하는 예외가 놓칠 수 있습니다. Unity에서는 라이프사이클 메서드를 async로 선언해도 됩니다. Start에서 명시적으로 await하고, Initialize에서는 더 이상 호출하지 않는 것이 깔끔합니다.
@@
- void Start()
- {
- Initialize();
- }
+ async void Start()
+ {
+ Initialize();
+ await LoadCharacter("zero");
+ }
@@
- // 임시로 zero 캐릭터 로드
- LoadCharacter("zero");
+ // 캐릭터 로드는 Start()에서 await로 처리Also applies to: 45-47
🤖 Prompt for AI Agents
In Assets/Domain/Character/Script/CharacterManager.cs around lines 23-26 (and
similarly 45-47), Start calls Initialize() without awaiting it, causing any
exceptions from the async LoadCharacter("zero") flow to be unobserved; make
Start async and explicitly await Initialize() there, and remove the internal
call to Initialize() from Initialize itself (or ensure Initialize no longer
invokes LoadCharacter synchronously) so the async flow is awaited at the
lifecycle entry point.
| [SerializeField] private ChatBubblePanel? _chatBubblePanel; | ||
| [SerializeField] private CharacterManager? _chracterManager; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
오탈자 필드명(_chracterManager) → 직렬화 호환 유지하며 정정 권장
가독성과 일관성을 위해 _characterManager로 변경하되, 씬/프리팹 직렬화가 깨지지 않도록 FormerlySerializedAs를 사용하세요.
using ProjectVG.Domain.Character.Service;
+using UnityEngine.Serialization;
@@
- [SerializeField] private CharacterManager? _chracterManager;
+ [SerializeField, FormerlySerializedAs("_chracterManager")] private CharacterManager? _characterManager;이후 사용처도 모두 _characterManager로 교체해야 합니다:
- if (_chracterManager != null)
+ if (_characterManager != null)
@@
- _chracterManager.PlayAction(listenAction);
+ _characterManager.PlayAction(listenAction);
@@
- if (_chracterManager != null)
+ if (_characterManager != null)
@@
- _chracterManager.PlayAction(chatMessage.ActionData);
+ _characterManager.PlayAction(chatMessage.ActionData);
@@
- if (_chracterManager != null)
+ if (_characterManager != null)
@@
- _chracterManager.PlayAction(idleAction);
+ _characterManager.PlayAction(idleAction);🤖 Prompt for AI Agents
In Assets/Domain/Chat/Service/ChatSystemManager.cs around lines 23-25, rename
the misspelled serialized field `_chracterManager` to `_characterManager` and
add the UnityEngine.Serialization.FormerlySerializedAs attribute pointing to "
_chracterManager" so scene/prefab serialization stays intact; also add or ensure
`using UnityEngine.Serialization;` is present at the top, then update every
usage in this file to the new `_characterManager` identifier.
| public void SetChatManager(ChatSystemManager chatManager) | ||
| { | ||
| _chatManager = chatManager; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
SetChatManager 시그니처 변경에 따른 호출부 정합성 확인 필요
메서드 시그니처가 SetChatManager(ChatSystemManager)로 변경되었습니다. 기존 호출부에서 구형 타입을 넘기던 곳이 있으면 컴파일 에러가 납니다. 리포지토리 전반 점검을 권장합니다.
다음 스크립트로 호출부를 점검하세요.
🏁 Script executed:
#!/bin/bash
# SetChatManager 호출부 점검
rg -nP --glob '!**/Library/**' --glob '!**/ProjectSettings/**' '\bSetChatManager\s*\(' -C2
# 구형 ChatManager 타입 직접 참조 점검
rg -nP --glob '!**/Library/**' --glob '!**/ProjectSettings/**' '\bChatManager\b' -C2Length of output: 59777
문서 예제 내 SetChatManager 시그니처 반영 필요
SetChatManager 메서드 시그니처가 ChatManager → ChatSystemManager로 변경되었으나, 코드 호출부는 존재하지 않아 컴파일 오류는 발생하지 않습니다. 다만 아래 README 문서의 예제에서는 여전히 _chatManager(ChatManager 타입)를 넘기고 있어 불일치가 발생하니, 문서 예제를 ChatSystemManager 사용 형태로 업데이트해야 합니다.
수정 대상:
- Assets/Domain/Chat/View/README_InputViews.md
• 예제 호출부 (_textInputView.SetChatManager(_chatManager);/_voiceInputView.SetChatManager(_chatManager);)
• 2834, 9099, 109112, 136143 라인 등
변경 예시:
- private ChatManager _chatManager;
+ private ChatSystemManager _chatSystemManager;
private void Start()
{
- _textInputView.SetChatManager(_chatManager);
- _voiceInputView.SetChatManager(_chatManager);
+ _textInputView.SetChatManager(_chatSystemManager);
+ _voiceInputView.SetChatManager(_chatSystemManager);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public void SetChatManager(ChatSystemManager chatManager) | |
| { | |
| _chatManager = chatManager; | |
| } | |
| private ChatSystemManager _chatSystemManager; | |
| private void Start() | |
| { | |
| _textInputView.SetChatManager(_chatSystemManager); | |
| _voiceInputView.SetChatManager(_chatSystemManager); | |
| } |
🤖 Prompt for AI Agents
In Assets/Domain/Chat/View/VoiceInputView.cs around lines 75 to 78, the
SetChatManager signature was changed from ChatManager to ChatSystemManager;
update the README examples accordingly: open
Assets/Domain/Chat/View/README_InputViews.md and replace example calls that pass
a ChatManager (e.g. _textInputView.SetChatManager(_chatManager);
_voiceInputView.SetChatManager(_chatManager);) with the ChatSystemManager type,
ensuring the variable names and type in the examples match the new signature
across the specified ranges (lines ~28–34, 90–99, 109–112, 136–143) so examples
compile and reflect current API.
87afe13 to
5945645
Compare
Summary by CodeRabbit
신규 기능
버그 수정
문서
기타