Merge remote-tracking branch 'origin/main'

This commit is contained in:
copecone committed 2026-08-18 14:16:52 +09:00
commit 838b0fccfd
4 files changed
+182 -179

No files matched your search

+5
View File
@@ -76,6 +76,11 @@ public class RenderSession
return this; return this;
} }
/// <summary>
/// Sets the custom output path for the rendered file.
/// </summary>
/// <param name="outputPath">The file path where the output will be saved, or <c>null</c> to use the default capture directory.</param>
/// <returns>The current <see cref="RenderSession"/> instance for method chaining.</returns>
public RenderSession WithOutputPath(string? outputPath) public RenderSession WithOutputPath(string? outputPath)
{ {
_outputPath = outputPath; _outputPath = outputPath;
+5 -5
View File
@@ -502,10 +502,12 @@ namespace ADOFAIRenderer.Core
var videoFPS = Configuration.VideoFPS; var videoFPS = Configuration.VideoFPS;
var startTime = DateTime.Now; var startTime = DateTime.Now;
var fileName = startTime.ToString("yyyy-MM-dd HH-mm-ss") + $".{Configuration.AdvancedConfig.Extension}";
_currentOutPath = Path.Combine(MelonEnvironment.GameRootDirectory, "Render", fileName);
if (RenderContext.OutputPath != null) _currentOutPath = RenderContext.OutputPath; if (RenderContext.OutputPath != null) _currentOutPath = RenderContext.OutputPath;
else {
var fileName = startTime.ToString("yyyy-MM-dd HH-mm-ss") +
$".{Configuration.AdvancedConfig.FileExtension.TrimStart('.').ToLower()}";
_currentOutPath = Path.Combine(MelonEnvironment.GameRootDirectory, "Render", fileName);
}
FFmpegNativeEncoder? videoFFmpeg = null; FFmpegNativeEncoder? videoFFmpeg = null;
try try
@@ -536,8 +538,6 @@ namespace ADOFAIRenderer.Core
videoFFmpeg = new FFmpegNativeEncoder(settings); videoFFmpeg = new FFmpegNativeEncoder(settings);
SetupCaptureDirectory();
_activeVideoFFmpeg = videoFFmpeg; _activeVideoFFmpeg = videoFFmpeg;
lock (_allVideoFFmpegInstances) lock (_allVideoFFmpegInstances)
{ {
+1 -1
View File
@@ -26,7 +26,7 @@ namespace ADOFAIRenderer.Data
public int? RandomSeed { get; set; } = null; public int? RandomSeed { get; set; } = null;
public bool ProcessAudio { get; set; } = true; public bool ProcessAudio { get; set; } = true;
public bool NonTile { get; set; } = false; public bool NonTile { get; set; } = false;
public string Extension { get; set; } = "mkv"; public string FileExtension { get; set; } = "mkv";
} }
public class VideoEncodingConfig public class VideoEncodingConfig
+171 -173
View File
@@ -124,7 +124,7 @@ namespace ADOFAIRenderer.UI
ProcessAudio = config.AdvancedConfig.ProcessAudio, ProcessAudio = config.AdvancedConfig.ProcessAudio,
RandomSeed = config.AdvancedConfig.RandomSeed, RandomSeed = config.AdvancedConfig.RandomSeed,
NonTile = config.AdvancedConfig.NonTile, NonTile = config.AdvancedConfig.NonTile,
Extension = config.AdvancedConfig.Extension FileExtension = config.AdvancedConfig.FileExtension
}; };
if (_advancedConfigContainer != null && _root.Contains(_advancedConfigContainer)) if (_advancedConfigContainer != null && _root.Contains(_advancedConfigContainer))
@@ -162,18 +162,18 @@ namespace ADOFAIRenderer.UI
_advancedConfigContainer.Add(titleRow); _advancedConfigContainer.Add(titleRow);
// 2. 확장자 로우 // 2. 확장자 로우
var extensionRow = CreateRow(); var fileExtensionRow = CreateRow();
var extensionLabel = CreateFormLabel("확장자"); var fileExtensionLabel = CreateFormLabel("확장자");
var extensionChoices = new List<string> { "mkv", "mp4", "mov", "webm", "avi" }; var fileExtensionChoices = new List<string> { "mkv", "mp4", "mov", "webm", "avi" };
var currentExt = string.IsNullOrWhiteSpace(tempConfig.Extension) ? "mkv" : tempConfig.Extension.TrimStart('.').ToLower(); var currentFileExt = string.IsNullOrWhiteSpace(tempConfig.FileExtension) ? "mkv" : tempConfig.FileExtension.TrimStart('.').ToLower();
if (!extensionChoices.Contains(currentExt)) if (!fileExtensionChoices.Contains(currentFileExt))
{ {
extensionChoices.Add(currentExt); fileExtensionChoices.Add(currentFileExt);
} }
var extensionDropdown = new DropdownField(extensionChoices, currentExt) { name = "AdvancedExtension" }; var fileExtensionDropdown = new DropdownField(fileExtensionChoices, currentFileExt) { name = "AdvancedFileExtension" };
extensionRow.Add(extensionLabel); fileExtensionRow.Add(fileExtensionLabel);
extensionRow.Add(extensionDropdown); fileExtensionRow.Add(fileExtensionDropdown);
_advancedConfigContainer.Add(extensionRow); _advancedConfigContainer.Add(fileExtensionRow);
// 3. 오디오 처리 로우 // 3. 오디오 처리 로우
var processAudioRow = CreateRow(); var processAudioRow = CreateRow();
@@ -227,7 +227,7 @@ namespace ADOFAIRenderer.UI
saveBtn.RegisterCallback<ClickEvent>(_ => saveBtn.RegisterCallback<ClickEvent>(_ =>
{ {
tempConfig.Extension = extensionDropdown.value; tempConfig.FileExtension = fileExtensionDropdown.value;
tempConfig.ProcessAudio = processAudioToggle.value; tempConfig.ProcessAudio = processAudioToggle.value;
tempConfig.NonTile = nonTileToggle.value; tempConfig.NonTile = nonTileToggle.value;
if (int.TryParse(randomSeedField.value?.Trim(), out var seed)) if (int.TryParse(randomSeedField.value?.Trim(), out var seed))
@@ -408,7 +408,7 @@ namespace ADOFAIRenderer.UI
modeDropdown.RegisterValueChangedCallback(evt => UpdateVisibility(evt.newValue)); modeDropdown.RegisterValueChangedCallback(evt => UpdateVisibility(evt.newValue));
qpField.RegisterValueChangedCallback(evt => qpField.RegisterValueChangedCallback(evt =>
{ {
warningRow.style.display = modeDropdown.value == RateControlMode.CQP.ToString() && evt.newValue == 0 warningRow.style.display = modeDropdown.value == nameof(RateControlMode.CQP) && evt.newValue == 0
? DisplayStyle.Flex ? DisplayStyle.Flex
: DisplayStyle.None; : DisplayStyle.None;
}); });
@@ -739,15 +739,21 @@ namespace ADOFAIRenderer.UI
_root.Remove(_presetConfigContainer); _root.Remove(_presetConfigContainer);
} }
_presetConfigContainer = new VisualElement { name = "PresetSettingsContainer" }; _presetConfigContainer = new VisualElement
_presetConfigContainer.style.position = Position.Absolute; {
_presetConfigContainer.style.width = Length.Percent(100); name = "PresetSettingsContainer",
_presetConfigContainer.style.height = Length.Percent(100); style =
_presetConfigContainer.style.left = 0; {
_presetConfigContainer.style.top = 0; position = Position.Absolute,
_presetConfigContainer.style.backgroundColor = new StyleColor(new Color(0.15f, 0.15f, 0.15f, 1.0f)); width = Length.Percent(100),
_presetConfigContainer.style.justifyContent = Justify.Center; height = Length.Percent(100),
_presetConfigContainer.style.alignItems = Align.Center; left = 0,
top = 0,
backgroundColor = new StyleColor(new Color(0.15f, 0.15f, 0.15f, 1.0f)),
justifyContent = Justify.Center,
alignItems = Align.Center
}
};
// Title Row // Title Row
var titleRow = CreateRow(); var titleRow = CreateRow();
@@ -837,152 +843,7 @@ namespace ADOFAIRenderer.UI
highButton.style.display = DisplayStyle.None; highButton.style.display = DisplayStyle.None;
} }
// Refresh Preset List RefreshPresets();
System.Action refreshPresets = null!;
refreshPresets = () =>
{
scrollView.Clear();
var presets = PresetManager.GetPresets();
if (presets.Count == 0)
{
var emptyRow = CreateRow();
emptyRow.style.height = StyleKeyword.Auto;
emptyRow.style.minHeight = StyleKeyword.Null;
emptyRow.style.maxHeight = StyleKeyword.Null;
var emptyLabel = new Label("저장된 프리셋이 없습니다.")
{
style =
{
color = new StyleColor(Color.gray),
unityTextAlign = TextAnchor.MiddleCenter,
marginTop = 80,
fontSize = 20
}
};
emptyRow.Add(emptyLabel);
scrollView.Add(emptyRow);
}
else
{
for (int i = 0; i < presets.Count; i++)
{
var preset = presets[i];
var itemRow = new VisualElement
{
style =
{
flexDirection = FlexDirection.Row,
justifyContent = Justify.SpaceBetween,
alignItems = Align.Center,
paddingBottom = 5,
paddingTop = 5,
borderBottomWidth = (i == presets.Count - 1) ? 0 : 1,
borderBottomColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.8f))
}
};
itemRow.AddToClassList("ui-row");
var nameLabel = new Label(preset.Name)
{
style =
{
color = new StyleColor(Color.white),
fontSize = 30,
flexGrow = 1
}
};
var btnContainer = new VisualElement
{
style = { flexDirection = FlexDirection.Row }
};
var loadBtn = new Button { text = "불러오기" };
loadBtn.style.marginRight = 10;
loadBtn.style.width = 180f;
loadBtn.style.marginTop = 0f;
loadBtn.style.marginBottom = 0f;
loadBtn.style.backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.22f, 1.0f));
loadBtn.style.borderTopColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f));
loadBtn.style.borderBottomColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f));
loadBtn.style.borderLeftColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f));
loadBtn.style.borderRightColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f));
loadBtn.style.borderTopWidth = 1f;
loadBtn.style.borderBottomWidth = 1f;
loadBtn.style.borderLeftWidth = 1f;
loadBtn.style.borderRightWidth = 1f;
loadBtn.style.borderTopLeftRadius = 8f;
loadBtn.style.borderTopRightRadius = 8f;
loadBtn.style.borderBottomLeftRadius = 8f;
loadBtn.style.borderBottomRightRadius = 8f;
loadBtn.style.paddingLeft = 10f;
loadBtn.style.paddingRight = 10f;
loadBtn.style.paddingTop = 10f;
loadBtn.style.paddingBottom = 10f;
loadBtn.style.fontSize = 30f;
loadBtn.style.height = 80f;
loadBtn.style.color = new StyleColor(Color.white);
loadBtn.RegisterCallback<ClickEvent>(_ =>
{
ApplyConfigToUI(preset.Config);
ToggleScreens(false);
_root.Remove(_presetConfigContainer);
_presetConfigContainer = null;
});
var deleteBtn = new Button { text = "삭제" };
deleteBtn.style.width = 120f;
deleteBtn.style.marginTop = 0f;
deleteBtn.style.marginBottom = 0f;
deleteBtn.style.backgroundColor = new StyleColor(new Color(0.25f, 0.12f, 0.12f, 1.0f));
deleteBtn.style.borderTopColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f));
deleteBtn.style.borderBottomColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f));
deleteBtn.style.borderLeftColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f));
deleteBtn.style.borderRightColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f));
deleteBtn.style.borderTopWidth = 1f;
deleteBtn.style.borderBottomWidth = 1f;
deleteBtn.style.borderLeftWidth = 1f;
deleteBtn.style.borderRightWidth = 1f;
deleteBtn.style.borderTopLeftRadius = 8f;
deleteBtn.style.borderTopRightRadius = 8f;
deleteBtn.style.borderBottomLeftRadius = 8f;
deleteBtn.style.borderBottomRightRadius = 8f;
deleteBtn.style.paddingLeft = 10f;
deleteBtn.style.paddingRight = 10f;
deleteBtn.style.paddingTop = 10f;
deleteBtn.style.paddingBottom = 10f;
deleteBtn.style.fontSize = 30f;
deleteBtn.style.height = 80f;
deleteBtn.style.color = new StyleColor(Color.white);
deleteBtn.RegisterCallback<ClickEvent>(_ =>
{
CommonWarningDialogUI.ShowDialog(
"프리셋 삭제",
$"'{preset.Name}' 프리셋을 정말 삭제하시겠습니까?",
new DialogButton("예", () =>
{
PresetManager.DeletePreset(preset.Name);
refreshPresets();
}),
new DialogButton("아니오", () => {})
);
});
btnContainer.Add(loadBtn);
btnContainer.Add(deleteBtn);
itemRow.Add(nameLabel);
itemRow.Add(btnContainer);
scrollView.Add(itemRow);
}
}
};
refreshPresets();
// Save row: Label + TextField + Save Button // Save row: Label + TextField + Save Button
var saveRow = CreateRow(); var saveRow = CreateRow();
@@ -991,10 +852,16 @@ namespace ADOFAIRenderer.UI
var nameLabelLabel = CreateFormLabel("새 프리셋 이름"); var nameLabelLabel = CreateFormLabel("새 프리셋 이름");
nameLabelLabel.style.marginRight = 10; nameLabelLabel.style.marginRight = 10;
var nameField = new TextField { label = "", name = "NewPresetName" }; var nameField = new TextField
nameField.style.width = 400; {
nameField.style.marginRight = 20; label = "", name = "NewPresetName",
style =
{
width = 400,
marginRight = 20
}
};
// 기존 폼 입력 필드 스타일과 맞춤 // 기존 폼 입력 필드 스타일과 맞춤
var textInput = nameField.Q("unity-text-input"); var textInput = nameField.Q("unity-text-input");
if (textInput != null) if (textInput != null)
@@ -1073,7 +940,7 @@ namespace ADOFAIRenderer.UI
PresetManager.SavePreset(presetName, currentConfig); PresetManager.SavePreset(presetName, currentConfig);
nameField.value = string.Empty; nameField.value = string.Empty;
refreshPresets(); RefreshPresets();
} }
catch (System.Exception ex) catch (System.Exception ex)
{ {
@@ -1108,6 +975,137 @@ namespace ADOFAIRenderer.UI
ToggleScreens(true); ToggleScreens(true);
return; return;
// Refresh Preset List
void RefreshPresets()
{
scrollView.Clear();
var presets = PresetManager.GetPresets();
if (presets.Count == 0)
{
var emptyRow = CreateRow();
emptyRow.style.height = StyleKeyword.Auto;
emptyRow.style.minHeight = StyleKeyword.Null;
emptyRow.style.maxHeight = StyleKeyword.Null;
var emptyLabel = new Label("저장된 프리셋이 없습니다.") { style = { color = new StyleColor(Color.gray), unityTextAlign = TextAnchor.MiddleCenter, marginTop = 80, fontSize = 20 } };
emptyRow.Add(emptyLabel);
scrollView.Add(emptyRow);
}
else
{
for (int i = 0; i < presets.Count; i++)
{
var preset = presets[i];
var itemRow = new VisualElement
{
style =
{
flexDirection = FlexDirection.Row,
justifyContent = Justify.SpaceBetween,
alignItems = Align.Center,
paddingBottom = 5,
paddingTop = 5,
borderBottomWidth = (i == presets.Count - 1) ? 0 : 1,
borderBottomColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.8f))
}
};
itemRow.AddToClassList("ui-row");
var nameLabel = new Label(preset.Name) { style = { color = new StyleColor(Color.white), fontSize = 30, flexGrow = 1 } };
var btnContainer = new VisualElement { style = { flexDirection = FlexDirection.Row } };
var loadBtn = new Button
{
text = "불러오기",
style =
{
marginRight = 10,
width = 180f,
marginTop = 0f,
marginBottom = 0f,
backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.22f, 1.0f)),
borderTopColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f)),
borderBottomColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f)),
borderLeftColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f)),
borderRightColor = new StyleColor(new Color(0.3f, 0.3f, 0.35f, 0.8f)),
borderTopWidth = 1f,
borderBottomWidth = 1f,
borderLeftWidth = 1f,
borderRightWidth = 1f,
borderTopLeftRadius = 8f,
borderTopRightRadius = 8f,
borderBottomLeftRadius = 8f,
borderBottomRightRadius = 8f,
paddingLeft = 10f,
paddingRight = 10f,
paddingTop = 10f,
paddingBottom = 10f,
fontSize = 30f,
height = 80f,
color = new StyleColor(Color.white)
}
};
loadBtn.RegisterCallback<ClickEvent>(_ =>
{
ApplyConfigToUI(preset.Config);
ToggleScreens(false);
_root.Remove(_presetConfigContainer);
_presetConfigContainer = null;
});
var deleteBtn = new Button
{
text = "삭제",
style =
{
width = 120f,
marginTop = 0f,
marginBottom = 0f,
backgroundColor = new StyleColor(new Color(0.25f, 0.12f, 0.12f, 1.0f)),
borderTopColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f)),
borderBottomColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f)),
borderLeftColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f)),
borderRightColor = new StyleColor(new Color(0.45f, 0.2f, 0.2f, 0.8f)),
borderTopWidth = 1f,
borderBottomWidth = 1f,
borderLeftWidth = 1f,
borderRightWidth = 1f,
borderTopLeftRadius = 8f,
borderTopRightRadius = 8f,
borderBottomLeftRadius = 8f,
borderBottomRightRadius = 8f,
paddingLeft = 10f,
paddingRight = 10f,
paddingTop = 10f,
paddingBottom = 10f,
fontSize = 30f,
height = 80f,
color = new StyleColor(Color.white)
}
};
deleteBtn.RegisterCallback<ClickEvent>(_ =>
{
CommonWarningDialogUI.ShowDialog("프리셋 삭제", $"'{preset.Name}' 프리셋을 정말 삭제하시겠습니까?", new DialogButton("예", () =>
{
PresetManager.DeletePreset(preset.Name);
RefreshPresets();
}), new DialogButton("아니오", () => { }));
});
btnContainer.Add(loadBtn);
btnContainer.Add(deleteBtn);
itemRow.Add(nameLabel);
itemRow.Add(btnContainer);
scrollView.Add(itemRow);
}
}
}
void ToggleScreens(bool showPreset) void ToggleScreens(bool showPreset)
{ {
if (_root.childCount > 0) if (_root.childCount > 0)