using System.IO;
using UnityEditor;
using UnityEngine;
using Colosseum.Combat.Simulation;
namespace Colosseum.Editor
{
///
/// 허수아비 계산 시뮬레이터 실행 창입니다.
///
public sealed class BuildSimulationWindow : EditorWindow
{
[SerializeField] private BuildSimulationInput buildInput = new BuildSimulationInput();
[SerializeField] private SimulationRuleSet ruleSet = new SimulationRuleSet();
[SerializeField] private RotationPolicy rotationPolicy = new RotationPolicy();
[SerializeField] private SimulationResult lastResult;
[SerializeField] private SimulationReportFormat previewFormat = SimulationReportFormat.DetailText;
private Vector2 scrollPosition;
[MenuItem("Tools/Colosseum/Simulation/Build Simulation Window")]
private static void Open()
{
BuildSimulationWindow window = GetWindow("Build Simulation");
window.minSize = new Vector2(520f, 640f);
window.Show();
}
private void OnGUI()
{
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
DrawBuildSection();
EditorGUILayout.Space(12f);
DrawRuleSection();
EditorGUILayout.Space(12f);
DrawRotationSection();
EditorGUILayout.Space(12f);
DrawRunSection();
EditorGUILayout.Space(12f);
DrawExportSection();
EditorGUILayout.Space(12f);
DrawResultSection();
EditorGUILayout.EndScrollView();
}
private void DrawBuildSection()
{
EditorGUILayout.LabelField("Build", EditorStyles.boldLabel);
SerializedObject serializedWindow = new SerializedObject(this);
SerializedProperty buildProperty = serializedWindow.FindProperty(nameof(buildInput));
DrawProperty(buildProperty, "buildName");
DrawProperty(buildProperty, "strength");
DrawProperty(buildProperty, "dexterity");
DrawProperty(buildProperty, "intelligence");
DrawProperty(buildProperty, "vitality");
DrawProperty(buildProperty, "wisdom");
DrawProperty(buildProperty, "spirit");
DrawProperty(buildProperty, "weapon");
DrawProperty(buildProperty, "directSkillSlots", true);
DrawProperty(buildProperty, "passiveTree");
DrawProperty(buildProperty, "selectedPassiveNodes", true);
DrawProperty(buildProperty, "passivePreset");
DrawProperty(buildProperty, "loadoutPreset");
serializedWindow.ApplyModifiedProperties();
}
private void DrawRuleSection()
{
EditorGUILayout.LabelField("Simulation", EditorStyles.boldLabel);
SerializedObject serializedWindow = new SerializedObject(this);
SerializedProperty ruleProperty = serializedWindow.FindProperty(nameof(ruleSet));
DrawProperty(ruleProperty, "ruleName");
DrawProperty(ruleProperty, "durationSeconds");
DrawProperty(ruleProperty, "targetCount");
DrawProperty(ruleProperty, "movementLossSecondsPerCast");
DrawProperty(ruleProperty, "manaRegenPerSecond");
serializedWindow.ApplyModifiedProperties();
}
private void DrawRotationSection()
{
EditorGUILayout.LabelField("Rotation", EditorStyles.boldLabel);
SerializedObject serializedWindow = new SerializedObject(this);
SerializedProperty rotationProperty = serializedWindow.FindProperty(nameof(rotationPolicy));
DrawProperty(rotationProperty, "policyName");
DrawProperty(rotationProperty, "prioritySlots", true);
DrawProperty(rotationProperty, "useFallbackSlot");
DrawProperty(rotationProperty, "fallbackSlotIndex");
DrawProperty(rotationProperty, "delayHighPowerSkillUntilTime");
if (rotationPolicy.DelayHighPowerSkillUntilTime)
{
DrawProperty(rotationProperty, "highPowerSlotIndex");
DrawProperty(rotationProperty, "highPowerFirstUseTime");
}
serializedWindow.ApplyModifiedProperties();
}
private void DrawRunSection()
{
EditorGUILayout.LabelField("Run", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("MVP 범위는 단일 대상 피해 계산입니다. 회복/보호막/위협과 버프성 효과는 이후 단계에서 확장합니다.", MessageType.Info);
using (new EditorGUI.DisabledScope(buildInput == null || buildInput.LoadoutPreset == null))
{
if (GUILayout.Button("Run Simulation", GUILayout.Height(32f)))
{
lastResult = BuildSimulationEngine.Run(buildInput, ruleSet, rotationPolicy);
if (lastResult != null && !string.IsNullOrWhiteSpace(lastResult.DetailText))
{
Debug.Log(lastResult.DetailText);
}
}
}
}
private void DrawResultSection()
{
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
if (lastResult == null)
{
EditorGUILayout.HelpBox("아직 실행 결과가 없습니다.", MessageType.None);
return;
}
EditorGUILayout.SelectableLabel(lastResult.SummaryLine, EditorStyles.textField, GUILayout.Height(36f));
previewFormat = (SimulationReportFormat)EditorGUILayout.EnumPopup("Format", previewFormat);
string previewText = SimulationReportUtility.BuildReport(lastResult, previewFormat);
EditorGUILayout.TextArea(previewText, GUILayout.MinHeight(260f));
}
private static void DrawProperty(SerializedProperty root, string relativePath, bool includeChildren = false)
{
SerializedProperty property = root.FindPropertyRelative(relativePath);
if (property != null)
{
EditorGUILayout.PropertyField(property, includeChildren);
}
}
private void DrawExportSection()
{
EditorGUILayout.LabelField("Export", EditorStyles.boldLabel);
if (lastResult == null)
{
EditorGUILayout.HelpBox("실행 결과가 생기면 복사와 저장 버튼이 활성화됩니다.", MessageType.None);
return;
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Copy Detail"))
{
CopyReport(SimulationReportFormat.DetailText);
}
if (GUILayout.Button("Copy Markdown"))
{
CopyReport(SimulationReportFormat.Markdown);
}
if (GUILayout.Button("Copy CSV"))
{
CopyReport(SimulationReportFormat.Csv);
}
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Save Markdown"))
{
SaveReport(SimulationReportFormat.Markdown);
}
if (GUILayout.Button("Save CSV"))
{
SaveReport(SimulationReportFormat.Csv);
}
}
}
private void CopyReport(SimulationReportFormat format)
{
string report = SimulationReportUtility.BuildReport(lastResult, format);
EditorGUIUtility.systemCopyBuffer = report;
Debug.Log($"[BuildSimulation] 결과를 클립보드에 복사했습니다. | Format={format}");
}
private void SaveReport(SimulationReportFormat format)
{
string extension = format == SimulationReportFormat.Csv ? "csv" : "md";
string defaultFileName = SimulationReportUtility.BuildDefaultFileName(lastResult, format);
string path = EditorUtility.SaveFilePanel(
"시뮬레이션 결과 저장",
Application.dataPath,
defaultFileName,
extension);
if (string.IsNullOrWhiteSpace(path))
return;
string report = SimulationReportUtility.BuildReport(lastResult, format);
File.WriteAllText(path, report);
Debug.Log($"[BuildSimulation] 결과 파일을 저장했습니다. | Path={path}");
}
}
}