diff --git a/Data/EnumDropdownBinder.cs b/Data/EnumDropdownBinder.cs
index d200ee2..f3b68e0 100644
--- a/Data/EnumDropdownBinder.cs
+++ b/Data/EnumDropdownBinder.cs
@@ -68,5 +68,19 @@ namespace ADOFAIRenderer.Data
callback(Value);
}
}
+
+ ///
+ /// Sets the selected enum value and updates the dropdown index.
+ ///
+ /// The enum value to set.
+ public void SetValue(T value)
+ {
+ if (_dropdown == null) return;
+ int idx = _values.IndexOf(value);
+ if (idx >= 0)
+ {
+ _dropdown.index = idx;
+ }
+ }
}
}
diff --git a/Data/PresetManager.cs b/Data/PresetManager.cs
new file mode 100644
index 0000000..76a9ce7
--- /dev/null
+++ b/Data/PresetManager.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using MelonLoader;
+using MelonLoader.Utils;
+using Newtonsoft.Json;
+
+namespace ADOFAIRenderer.Data
+{
+ public class RenderPreset
+ {
+ public string Name { get; set; } = string.Empty;
+ public RenderConfig Config { get; set; } = null!;
+ }
+
+ public static class PresetManager
+ {
+ private static string GetPresetsDirectory()
+ {
+ return Path.Combine(MelonEnvironment.GameRootDirectory, "UserData", "ADOFAIRenderer", "Presets");
+ }
+
+ private static string GetSafeFileName(string name)
+ {
+ return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, '_'));
+ }
+
+ public static void SavePreset(string name, RenderConfig config)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("프리셋 이름은 비어 있을 수 없습니다.");
+ }
+
+ string dir = GetPresetsDirectory();
+ if (!Directory.Exists(dir))
+ {
+ Directory.CreateDirectory(dir);
+ }
+
+ var preset = new RenderPreset
+ {
+ Name = name,
+ Config = config
+ };
+
+ string json = JsonConvert.SerializeObject(preset, Formatting.Indented);
+ string safeName = GetSafeFileName(name);
+ string filePath = Path.Combine(dir, safeName + ".json");
+ File.WriteAllText(filePath, json);
+ }
+
+ public static List GetPresets()
+ {
+ var presets = new List();
+ string dir = GetPresetsDirectory();
+ if (!Directory.Exists(dir))
+ {
+ return presets;
+ }
+
+ try
+ {
+ string[] files = Directory.GetFiles(dir, "*.json");
+ foreach (string file in files)
+ {
+ try
+ {
+ string json = File.ReadAllText(file);
+ var preset = JsonConvert.DeserializeObject(json);
+ if (preset != null && !string.IsNullOrEmpty(preset.Name) && preset.Config != null)
+ {
+ presets.Add(preset);
+ }
+ }
+ catch (Exception ex)
+ {
+ MelonLogger.Warning($"프리셋 파일 '{Path.GetFileName(file)}' 로드 중 오류 발생: {ex.Message}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ MelonLogger.Error($"프리셋 목록을 불러오는 중 오류 발생: {ex.Message}");
+ }
+
+ return presets;
+ }
+
+ public static void DeletePreset(string name)
+ {
+ string dir = GetPresetsDirectory();
+ string safeName = GetSafeFileName(name);
+ string filePath = Path.Combine(dir, safeName + ".json");
+
+ if (File.Exists(filePath))
+ {
+ File.Delete(filePath);
+ }
+ }
+ }
+}
diff --git a/Data/RenderConfig.cs b/Data/RenderConfig.cs
index 2de90c3..19e12ca 100644
--- a/Data/RenderConfig.cs
+++ b/Data/RenderConfig.cs
@@ -4,31 +4,31 @@ namespace ADOFAIRenderer.Data
{
public class RenderConfig
{
- public double RenderFPS;
- public double VideoFPS;
+ public double RenderFPS { get; set; }
+ public double VideoFPS { get; set; }
- public int RenderWidth;
- public int RenderHeight;
+ public int RenderWidth { get; set; }
+ public int RenderHeight { get; set; }
- public Codec Codec;
- public EncodingConfig? EncodingConfig;
+ public Codec Codec { get; set; }
+ public EncodingConfig? EncodingConfig { get; set; }
- public double DelayAfterLevelEnd;
- public bool ShowJudgementText;
+ public double DelayAfterLevelEnd { get; set; }
+ public bool ShowJudgementText { get; set; }
- public int? RandomSeed = null;
- public bool ProcessAudio;
+ public int? RandomSeed { get; set; } = null;
+ public bool ProcessAudio { get; set; }
}
public class EncodingConfig
{
- public RateControlMode RateControlMode;
+ public RateControlMode RateControlMode { get; set; }
- public int Bitrate;
- public int MaxBitrate;
+ public int Bitrate { get; set; }
+ public int MaxBitrate { get; set; }
// ReSharper disable once InconsistentNaming
- public int QP;
- public double KeyframeInterval;
- public bool ForceSoftwareEncoder;
+ public int QP { get; set; }
+ public double KeyframeInterval { get; set; }
+ public bool ForceSoftwareEncoder { get; set; }
}
}
\ No newline at end of file
diff --git a/UI/RenderConfigUIManager.cs b/UI/RenderConfigUIManager.cs
index 1dabc36..4f9acab 100644
--- a/UI/RenderConfigUIManager.cs
+++ b/UI/RenderConfigUIManager.cs
@@ -63,6 +63,17 @@ namespace ADOFAIRenderer.UI
{
Melon.Logger.Error("Button 'EncodingSettingsButton'을(를) 찾을 수 없습니다.");
}
+
+ var presetSettingsButton = _root.Q