diff --git a/Core/FirstUpdateHook.cs b/Core/FirstUpdateHook.cs
index b0d5d7e..14a85ab 100644
--- a/Core/FirstUpdateHook.cs
+++ b/Core/FirstUpdateHook.cs
@@ -45,20 +45,20 @@ internal class FirstUpdateHook : MonoBehaviour
var currentVersion = driverVer.Value.ToString("F2");
CommonWarningDialogUI.ShowDialog(
- "NVIDIA 그래픽 드라이버 업데이트 권장",
- $"현재 감지된 NVIDIA 그래픽 드라이버 버전: {currentVersion}\n\n하드웨어 가속(NVENC)을 사용하여 영상을 렌더링하려면 드라이버 버전 610.00 이상이 필요합니다.\n\n드라이버 버전이 낮으면 인코딩이 실패하거나 소프트웨어(CPU) 인코딩으로 대체되어 렌더링이 매우 느려집니다. 드라이버 업데이트를 진행해 주시기 바랍니다.",
- new DialogButton("드라이버 업데이트", () =>
+ "NVIDIA Graphics Driver Update Recommended",
+ $"Currently detected NVIDIA graphics driver version: {currentVersion}\n\nDriver version 610.00 or higher is required to render video using hardware acceleration (NVENC).\n\nIf the driver version is lower, encoding may fail or fallback to software (CPU) encoding, significantly slowing down rendering. Please update your graphics driver.",
+ new DialogButton("Update Driver", () =>
{
Application.OpenURL("https://www.nvidia.com/Download/index.aspx");
Application.Quit();
}, new Color(0.0f, 0.8f, 1.0f, 1.0f)),
- new DialogButton("기능 비활성화", () =>
+ new DialogButton("Disable Feature", () =>
{
RenderMod.IsFeatureDisabled = true;
}),
- new DialogButton("이번만 그냥 진행", () =>
+ new DialogButton("Continue Anyway", () =>
{
- // 아무 동작 안 함
+ // ignored
})
);
}
diff --git a/Core/RenderManager.cs b/Core/RenderManager.cs
index 0df152e..c3d0c16 100644
--- a/Core/RenderManager.cs
+++ b/Core/RenderManager.cs
@@ -40,10 +40,10 @@ internal static class RenderContext
if (result.Success && Notification)
{
var fileString = !string.IsNullOrEmpty(RenderManager.Instance.CurrentOutPath) ?
- $"'{Path.GetFileName(RenderManager.Instance.CurrentOutPath)}'이(가)" : "동영상이";
+ $"'{Path.GetFileName(RenderManager.Instance.CurrentOutPath)}'" : "Video";
var renderFolder = Path.GetDirectoryName(RenderManager.Instance.CurrentOutPath);
- OSNotification.Show("렌더링 완료!", $"{fileString} 성공적으로 저장되었습니다.", renderFolder);
+ OSNotification.Show("Rendering Complete!", $"{fileString} saved successfully.", renderFolder);
}
};
public static Action OnComplete = OnCompleteDefault;
@@ -178,7 +178,7 @@ internal class RenderManager : MonoBehaviour
if (_activeVideoFFmpeg != null)
{
- Melon.Logger.Msg("게임 종료 또는 RenderManager 파괴 감지: FFmpeg 네이티브 인코더 리소스를 해제합니다.");
+ Melon.Logger.Msg("Game exit or RenderManager destruction detected: Disposing FFmpeg native encoder resources.");
_activeVideoFFmpeg.Dispose();
_activeVideoFFmpeg = null;
}
@@ -187,7 +187,7 @@ internal class RenderManager : MonoBehaviour
{
if (_allVideoFFmpegInstances.Count > 0)
{
- Melon.Logger.Msg($"게임 종료 감지: 생성된 모든 FFmpeg 인코더 인스턴스({_allVideoFFmpegInstances.Count}개)를 수거 및 해제합니다.");
+ Melon.Logger.Msg($"Game exit detected: Cleaning up and disposing all created FFmpeg encoder instances ({_allVideoFFmpegInstances.Count}).");
foreach (var instance in _allVideoFFmpegInstances)
{
try
@@ -196,7 +196,7 @@ internal class RenderManager : MonoBehaviour
}
catch
{
- // Ignore
+ // ignored
}
}
_allVideoFFmpegInstances.Clear();
@@ -278,18 +278,18 @@ internal class RenderManager : MonoBehaviour
{
if (!IsRendering) return;
- // [렉으로 인한 프레임 렌더링 스킵 시 재시도 로직 (원본 모드 이식)]
+ // [Retry logic when frame rendering is skipped due to lag (ported from original mod)]
if (renderCheck && IsCapturing)
{
if (skipCount < MaxRenderRetry)
{
Melon.Logger.Warning($"[Render Skipped] Frame {frameCount} rendering missed. Retrying... (Attempt {skipCount + 1}/{MaxRenderRetry})");
skipCount++;
- Time.timeScale = 0f; // 진행 시간 멈추기 (재시도)
- return; // 업데이트 진행하지 않고 대기
+ Time.timeScale = 0f; // Pause progress time (retry)
+ return; // Wait without advancing update
}
- // 60회 초과 시 최후의 블랙 프레임 삽입하여 전체 파이프라인 마비 방지
+ // If retries exceed limit, supply a fallback black frame to prevent freezing the pipeline
Melon.Logger.Error($"[Render Skipped] Frame {frameCount} rendering failed after 60 retries. Supplying black frame.");
var currentFrame = frameCountForVideo++;
@@ -318,11 +318,11 @@ internal class RenderManager : MonoBehaviour
FrameAvailableEvent.Set();
}
- renderCheck = false; // 진행 허용
+ renderCheck = false; // Allow progress
}
skipCount = 0;
- renderCheck = true; // 다음 프레임 검사용으로 초기화
+ renderCheck = true; // Reset for next frame check
frameCount++;
}
@@ -344,9 +344,9 @@ internal class RenderManager : MonoBehaviour
{
if (!IsCapturing || !texture) return;
- renderCheck = false; // 이번 프레임 정상 렌더링 완료
+ renderCheck = false; // Normal rendering complete for this frame
- // [Backpressure Throttling (2번 작업)]
+ // [Backpressure Throttling]
isThrottling = false;
while (IsCapturing && IsRendering)
@@ -458,11 +458,11 @@ internal class RenderManager : MonoBehaviour
}
catch (Exception ex)
{
- Melon.Logger.Error($"인코더 초기화 에러: {ex}");
+ Melon.Logger.Error($"Encoder initialization error: {ex}");
CommonWarningDialogUI.ShowDialog(
- "인코더 오류",
- $"비디오 인코더를 초기화할 수 없습니다.\n오류: {ex.Message}",
- new DialogButton("확인", () =>
+ "Encoder Error",
+ $"Failed to initialize video encoder.\nError: {ex.Message}",
+ new DialogButton("OK", () =>
{
ADOBase.loader.LoadSceneWithTransition(WipeDirection.StartsFromRight, "scnEditor");
})
@@ -676,7 +676,7 @@ internal class RenderManager : MonoBehaviour
}
catch (Exception ex)
{
- Melon.Logger.Error($"FFmpeg 렌더링 스레드 오류: {ex}");
+ Melon.Logger.Error($"FFmpeg rendering thread error: {ex}");
videoFFmpeg.Dispose();
lock (_allVideoFFmpegInstances)
{
@@ -720,22 +720,22 @@ internal class RenderManager : MonoBehaviour
if (success) StartCoroutine(StopRenderCoroutine());
else
{
- Melon.Logger.Error("렌더링이 실패했거나 취소되었습니다. 상태 및 리소스를 안전하게 청소합니다.");
+ Melon.Logger.Error("Rendering failed or was cancelled. Safely cleaning up state and resources.");
- // 1. 렌더링 백그라운드 스레드가 큐에 유입된 잔여 프레임 처리를 마무리하고 종료될 때까지 대기
+ // 1. Wait for render background thread to finish processing remaining queued frames and terminate
if (RenderThread is { IsAlive: true })
{
RenderThread.Join(2000);
}
- // 2. 스레드 종료 보장 후, 안전하게 FFmpeg 네이티브 인코더 리소스 해제
+ // 2. After ensuring thread termination, safely release FFmpeg native encoder resources
if (_activeVideoFFmpeg != null)
{
_activeVideoFFmpeg.Dispose();
_activeVideoFFmpeg = null;
}
- // 3. 메모리 누수 방지: 큐에 렌트된 임시 프레임 버퍼 풀 반환 및 클리어
+ // 3. Memory leak prevention: Return rented temporary frame buffer pool in queue and clear
lock (ImageQueue)
{
foreach (var kvp in ImageQueue.Values)
@@ -754,14 +754,14 @@ internal class RenderManager : MonoBehaviour
_frameReader?.Dispose();
- // 디버그 모니터 UI 정리
+ // Clean up Debug Monitor UI
if (_debugMonitorObj)
{
Destroy(_debugMonitorObj);
_debugMonitorObj = null;
}
- // 4. 인게임 카메라 및 렌더링용 RTCam 상태 안전 원복
+ // 4. Safely restore in-game camera and RTCam state for rendering
if (scrCamera.instance)
{
scrCamera.instance.forceRTCam = false;
@@ -771,24 +771,24 @@ internal class RenderManager : MonoBehaviour
if (hook) Destroy(hook);
}
- // 5. 인게임 실패 방지 플래그 원상 복구
+ // 5. Restore in-game no-fail flags
if (scrController.instance)
{
scrController.instance.noFail = false;
scrController.instance.noFailInfiniteMargin = false;
}
- // 6. 취소된 미완성 임시 동영상 파일 즉각 삭제
+ // 6. Immediately delete cancelled incomplete temporary video file
if (!string.IsNullOrEmpty(CurrentOutPath) && File.Exists(CurrentOutPath))
{
try
{
File.Delete(CurrentOutPath);
- Melon.Logger.Msg($"[File Cleanup] 미완성 동영상 삭제 완료: {CurrentOutPath}");
+ Melon.Logger.Msg($"[File Cleanup] Deleted incomplete video: {CurrentOutPath}");
}
catch (Exception ex)
{
- Melon.Logger.Error($"[File Cleanup] 임시 동영상 삭제 실패: {ex.Message}");
+ Melon.Logger.Error($"[File Cleanup] Failed to delete temporary video: {ex.Message}");
}
CurrentOutPath = null;
}
diff --git a/Data/DoubleLimit.cs b/Data/DoubleLimit.cs
index 92fe984..dd45b3d 100644
--- a/Data/DoubleLimit.cs
+++ b/Data/DoubleLimit.cs
@@ -31,7 +31,7 @@ internal class PositiveOnlyDoubleLimit : DoubleLimit
return true;
}
- errorMessage = "값은 0보다 큰 양수여야 합니다.";
+ errorMessage = "Value must be a positive number greater than 0.";
return false;
}
}
@@ -60,16 +60,16 @@ internal class RangeDoubleLimit : DoubleLimit
if (value < Min)
{
errorMessage = Max.HasValue
- ? $"값은 {Min.Value}에서 {Max.Value} 사이의 숫자여야 합니다."
- : $"값은 {Min.Value} 이상의 숫자여야 합니다.";
+ ? $"Value must be a number between {Min.Value} and {Max.Value}."
+ : $"Value must be a number greater than or equal to {Min.Value}.";
return false;
}
if (value > Max)
{
errorMessage = Min.HasValue
- ? $"값은 {Min.Value}에서 {Max.Value} 사이의 숫자여야 합니다."
- : $"값은 {Max.Value} 이하의 숫자여야 합니다.";
+ ? $"Value must be a number between {Min.Value} and {Max.Value}."
+ : $"Value must be a number less than or equal to {Max.Value}.";
return false;
}
diff --git a/Data/Input/DoubleInputValidator.cs b/Data/Input/DoubleInputValidator.cs
index 65de249..f5bb42f 100644
--- a/Data/Input/DoubleInputValidator.cs
+++ b/Data/Input/DoubleInputValidator.cs
@@ -53,7 +53,7 @@ internal class DoubleInputValidator
if (field == null)
{
Melon.Logger.Warning(
- $"DoubleField '{fieldName}'을(를) 찾을 수 없습니다. 유효성 검사를 건너뜁니다.");
+ $"DoubleField '{fieldName}' not found. Skipping validation.");
continue;
}
diff --git a/Data/Input/EnumDropdownBinder.cs b/Data/Input/EnumDropdownBinder.cs
index 6e0e88d..6e4d3cc 100644
--- a/Data/Input/EnumDropdownBinder.cs
+++ b/Data/Input/EnumDropdownBinder.cs
@@ -41,7 +41,7 @@ internal class EnumDropdownBinder where T : struct, Enum
if (_dropdown == null)
{
Melon.Logger.Error(
- $"DropdownField '{fieldName}'을(를) 찾을 수 없습니다.");
+ $"DropdownField '{fieldName}' not found.");
return;
}
diff --git a/Data/Input/IntegerInputValidator.cs b/Data/Input/IntegerInputValidator.cs
index f19bd68..e59df8b 100644
--- a/Data/Input/IntegerInputValidator.cs
+++ b/Data/Input/IntegerInputValidator.cs
@@ -53,7 +53,7 @@ internal class IntegerInputValidator
if (field == null)
{
Melon.Logger.Warning(
- $"IntegerField '{fieldName}'을(를) 찾을 수 없습니다. 유효성 검사를 건너뜁니다.");
+ $"IntegerField '{fieldName}' not found. Skipping validation.");
continue;
}
diff --git a/Data/IntegerLimit.cs b/Data/IntegerLimit.cs
index 01496b4..f118b91 100644
--- a/Data/IntegerLimit.cs
+++ b/Data/IntegerLimit.cs
@@ -31,7 +31,7 @@ internal class PositiveOnlyIntegerLimit : IntegerLimit
return true;
}
- errorMessage = "값은 0보다 큰 양의 정수여야 합니다.";
+ errorMessage = "Value must be a positive integer greater than 0.";
return false;
}
}
@@ -60,16 +60,16 @@ internal class RangeIntegerLimit : IntegerLimit
if (value < Min)
{
errorMessage = Max.HasValue
- ? $"값은 {Min.Value}에서 {Max.Value} 사이의 정수여야 합니다."
- : $"값은 {Min.Value} 이상의 정수여야 합니다.";
+ ? $"Value must be an integer between {Min.Value} and {Max.Value}."
+ : $"Value must be an integer greater than or equal to {Min.Value}.";
return false;
}
if (value > Max)
{
errorMessage = Min.HasValue
- ? $"값은 {Min.Value}에서 {Max.Value} 사이의 정수여야 합니다."
- : $"값은 {Max.Value} 이하의 정수여야 합니다.";
+ ? $"Value must be an integer between {Min.Value} and {Max.Value}."
+ : $"Value must be an integer less than or equal to {Max.Value}.";
return false;
}
diff --git a/Data/PresetManager.cs b/Data/PresetManager.cs
index d4393d3..dfb41c5 100644
--- a/Data/PresetManager.cs
+++ b/Data/PresetManager.cs
@@ -31,7 +31,7 @@ internal static class PresetManager
{
if (string.IsNullOrWhiteSpace(name))
{
- throw new ArgumentException("프리셋 이름은 비어 있을 수 없습니다.");
+ throw new ArgumentException("Preset name cannot be empty.");
}
string dir = GetPresetsDirectory();
@@ -154,13 +154,13 @@ internal static class PresetManager
}
catch (Exception ex)
{
- MelonLogger.Warning($"프리셋 파일 '{Path.GetFileName(file)}' 로드 중 오류 발생: {ex.Message}");
+ MelonLogger.Warning($"Error loading preset file '{Path.GetFileName(file)}': {ex.Message}");
}
}
}
catch (Exception ex)
{
- MelonLogger.Error($"프리셋 목록을 불러오는 중 오류 발생: {ex.Message}");
+ MelonLogger.Error($"Error retrieving preset list: {ex.Message}");
}
return presets;
diff --git a/Patch/Game/scnEditorPatch.cs b/Patch/Game/scnEditorPatch.cs
index ab904af..8698c0e 100644
--- a/Patch/Game/scnEditorPatch.cs
+++ b/Patch/Game/scnEditorPatch.cs
@@ -18,7 +18,7 @@ public static class scnEditorPatch
if (RenderMod.IsFeatureDisabled) return;
if (!__instance || !__instance.buttonExit)
{
- Melon.Logger.Msg("scnEditor에 렌더 버튼을 만들 수 없습니다.");
+ Melon.Logger.Msg("Cannot create render button in scnEditor.");
return;
}
diff --git a/RenderMod.cs b/RenderMod.cs
index bd5c936..cfc3dea 100644
--- a/RenderMod.cs
+++ b/RenderMod.cs
@@ -48,11 +48,11 @@ namespace ADOFAIRenderer
{
ShaderBundle = BundleLoader.GetBundle("shaders");
ColorConversionShader = ShaderBundle.LoadAsset("ColorConversion");
- Melon.Logger.Msg("컬러 변환 Compute Shader 로드 완료.");
+ Melon.Logger.Msg("Color conversion Compute Shader loaded successfully.");
}
catch (Exception ex)
{
- Melon.Logger.Warning($"Shader 에셋번들을 로드할 수 없습니다. GPU 컬러 변환이 비활성화되며 CPU로 폴백합니다. 에러: {ex.Message}");
+ Melon.Logger.Warning($"Failed to load Shader AssetBundle. GPU color conversion will be disabled and fallback to CPU. Error: {ex.Message}");
}
}
@@ -62,7 +62,7 @@ namespace ADOFAIRenderer
var currentModule = EventSystem.current.currentInputModule;
if (currentModule) return;
- Melon.Logger.Msg("Unity 6 인풋 모듈 이식.");
+ Melon.Logger.Msg("Ported Unity 6 Input Module.");
var newModule = EventSystem.current.gameObject.AddComponent();
newModule.enabled = true;
@@ -71,7 +71,7 @@ namespace ADOFAIRenderer
public override void OnApplicationQuit()
{
if (RenderManager.Instance == null) return;
- Melon.Logger.Msg("MelonLoader 종료 감지: RenderManager의 활성 프로세스를 강제 수거 및 종료합니다.");
+ Melon.Logger.Msg("MelonLoader shutdown detected: Forcefully terminating and cleaning up active RenderManager processes.");
RenderManager.Instance.CleanUpActiveRender();
}
}
diff --git a/UI/CommonWarningDialogUI.cs b/UI/CommonWarningDialogUI.cs
index aa5d67c..a26bd96 100644
--- a/UI/CommonWarningDialogUI.cs
+++ b/UI/CommonWarningDialogUI.cs
@@ -63,11 +63,11 @@ internal class CommonWarningDialogUI : MonoBehaviour
}
catch
{
- // 로딩 실패
+ // Loading failed
}
}
- // 폴백 처리
+ // Fallback processing
if (!font)
{
try
@@ -121,15 +121,15 @@ internal class CommonWarningDialogUI : MonoBehaviour
}
}
- // UI 레이어(5) 설정
+ // Set UI layer (5)
gameObject.layer = 5;
- // Canvas 설정
+ // Canvas setup
var canvas = gameObject.AddComponent