#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) { }
}
}