#nullable enable using System.Collections.Generic; using UnityEngine; using UVC.UI.Commands; using UVC.Studio.Manager; using UVC.Studio.Config; namespace UVC.Studio.Command { /// /// 복제 커맨드 (Undo/Redo 지원) /// TransformChangeCommand가 StageObjectId로 Transform을 복원하므로 /// 이 커맨드는 객체 생성/삭제만 담당합니다. /// public class EditDuplicateCommand : IUndoableCommand { public string Description => "객체 복제"; private readonly SelectionManager _selectionManager; private readonly StageObjectManager _stageObjectManager; // Undo용 상태 저장 private readonly List _duplicatedObjects = new(); /// /// 복제된 객체 데이터 /// private class DuplicatedObjectData { public string StageObjectId { get; set; } = string.Empty; public GameObject? GameObject { get; set; } public EquipmentItem? Equipment { get; set; } public Vector3 InitialPosition { get; set; } public Quaternion InitialRotation { get; set; } public Vector3 InitialScale { get; set; } } public EditDuplicateCommand(SelectionManager selectionManager, StageObjectManager stageObjectManager) { _selectionManager = selectionManager; _stageObjectManager = stageObjectManager; } public void Execute(object? parameter = null) { _duplicatedObjects.Clear(); var selectedObjects = new List(_selectionManager.SelectedObjects); if (selectedObjects.Count == 0) { Debug.Log("[EditDuplicateCommand] 선택된 객체가 없습니다."); return; } // 복제된 StageObject 목록 (선택 상태 변경용) var duplicatedStageObjects = new List(); foreach (var stageObject in selectedObjects) { if (stageObject.GameObject == null) continue; // GameObject 복제 var clone = Object.Instantiate(stageObject.GameObject); // Stage를 부모로 설정 var studioMain = StudioSceneMain.Instance; if (studioMain != null && studioMain.Stage != null) { clone.transform.SetParent(studioMain.Stage.transform); } // Layer 설정 clone.layer = LayerMask.NameToLayer("Model"); clone.transform.position += new Vector3(1f, 0f, 1f); // 약간 이동 // StageObjectManager에 등록 var newStageObject = _stageObjectManager.Register(stageObject.Equipment, clone); duplicatedStageObjects.Add(newStageObject); // Undo용 데이터 저장 var data = new DuplicatedObjectData { StageObjectId = newStageObject.Id, GameObject = clone, Equipment = stageObject.Equipment, InitialPosition = clone.transform.localPosition, InitialRotation = clone.transform.localRotation, InitialScale = clone.transform.localScale }; _duplicatedObjects.Add(data); } // 원본 선택 해제 후 복제된 객체들 선택 if (duplicatedStageObjects.Count > 0) { _selectionManager.DeselectAll(); foreach (var stageObject in duplicatedStageObjects) { _selectionManager.Select(stageObject, addToSelection: true); } } Debug.Log($"[EditDuplicateCommand] {_duplicatedObjects.Count}개 객체 복제됨 (선택 전환됨)"); } public void Undo(object? parameter = null) { // SelectionManager에서 삭제할 객체들 선택 해제 foreach (var data in _duplicatedObjects) { var stageObject = _stageObjectManager.GetById(data.StageObjectId); if (stageObject != null) { _selectionManager.Deselect(stageObject); } } // 복제된 객체들 제거 foreach (var data in _duplicatedObjects) { _stageObjectManager.Unregister(data.StageObjectId); data.GameObject = null; } Debug.Log($"[EditDuplicateCommand] Undo: {_duplicatedObjects.Count}개 객체 복제 취소됨"); } public void Redo() { // 재생성된 StageObject 목록 (선택 상태 복원용) var recreatedStageObjects = new List(); foreach (var data in _duplicatedObjects) { if (data.Equipment == null) continue; // 원본 객체 찾기 (동일 Equipment를 가진 객체) GameObject? templateObject = null; foreach (var kvp in _stageObjectManager.Objects) { if (kvp.Value.Equipment != null && kvp.Value.Equipment.id == data.Equipment.id && kvp.Value.GameObject != null) { templateObject = kvp.Value.GameObject; break; } } if (templateObject == null) continue; // 다시 복제 var clone = Object.Instantiate(templateObject); // Stage를 부모로 설정 var studioMain = StudioSceneMain.Instance; if (studioMain != null && studioMain.Stage != null) { clone.transform.SetParent(studioMain.Stage.transform); } // Layer 설정 clone.layer = LayerMask.NameToLayer("Model"); // 동일한 ID로 재등록 (TransformChangeCommand가 ID로 찾을 수 있도록) var newStageObject = _stageObjectManager.RegisterWithId(data.StageObjectId, data.Equipment, clone); recreatedStageObjects.Add(newStageObject); // GameObject 참조 업데이트 data.GameObject = clone; // 초기 Transform 상태 적용 clone.transform.localPosition = data.InitialPosition; clone.transform.localRotation = data.InitialRotation; clone.transform.localScale = data.InitialScale; } // SelectionManager에 재생성된 객체들 선택 if (recreatedStageObjects.Count > 0) { _selectionManager.DeselectAll(); foreach (var stageObject in recreatedStageObjects) { _selectionManager.Select(stageObject, addToSelection: true); } } Debug.Log($"[EditDuplicateCommand] Redo: {_duplicatedObjects.Count}개 객체 복제 재실행됨"); } public bool CanMerge(IUndoableCommand other) => false; public void Merge(IUndoableCommand other) { } } }