197 lines
7.3 KiB
C#
197 lines
7.3 KiB
C#
|
|
#nullable enable
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEngine;
|
||
|
|
using UVC.UI.Commands;
|
||
|
|
using UVC.Studio.Manager;
|
||
|
|
using UVC.Studio.Config;
|
||
|
|
|
||
|
|
namespace UVC.Studio.Command
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 복제 커맨드 (Undo/Redo 지원)
|
||
|
|
/// TransformChangeCommand가 StageObjectId로 Transform을 복원하므로
|
||
|
|
/// 이 커맨드는 객체 생성/삭제만 담당합니다.
|
||
|
|
/// </summary>
|
||
|
|
public class EditDuplicateCommand : IUndoableCommand
|
||
|
|
{
|
||
|
|
public string Description => "객체 복제";
|
||
|
|
|
||
|
|
private readonly SelectionManager _selectionManager;
|
||
|
|
private readonly StageObjectManager _stageObjectManager;
|
||
|
|
|
||
|
|
// Undo용 상태 저장
|
||
|
|
private readonly List<DuplicatedObjectData> _duplicatedObjects = new();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 복제된 객체 데이터
|
||
|
|
/// </summary>
|
||
|
|
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<StageObjectManager.StageObject>(_selectionManager.SelectedObjects);
|
||
|
|
if (selectedObjects.Count == 0)
|
||
|
|
{
|
||
|
|
Debug.Log("[EditDuplicateCommand] 선택된 객체가 없습니다.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 복제된 StageObject 목록 (선택 상태 변경용)
|
||
|
|
var duplicatedStageObjects = new List<StageObjectManager.StageObject>();
|
||
|
|
|
||
|
|
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<StageObjectManager.StageObject>();
|
||
|
|
|
||
|
|
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) { }
|
||
|
|
}
|
||
|
|
}
|