SHA256
forked from ADOFAIEditorForum/ADOFAIRenderer
Add Escape Feature
This commit is contained in:
1 parent
0b4a772933
commit
fb97a85875
4 files changed
+224
-9
No files matched your search
@@ -19,6 +19,8 @@ namespace ADOFAIRenderer.Component
|
||||
public static RenderManager Instance = null!;
|
||||
private static int _originalInputOffset;
|
||||
private static GameObject? _debugMonitorObj;
|
||||
private static GameObject? _escapeHandlerObj;
|
||||
private static string? _currentOutPath;
|
||||
|
||||
public static RenderSettings Configuration;
|
||||
|
||||
@@ -96,6 +98,13 @@ namespace ADOFAIRenderer.Component
|
||||
RenderMod.IsRendering = true;
|
||||
Countdown = 3;
|
||||
|
||||
if (!_escapeHandlerObj)
|
||||
{
|
||||
_escapeHandlerObj = new GameObject("EscapeHandlerCanvas");
|
||||
_escapeHandlerObj.AddComponent<EscapeHandlerUI>();
|
||||
DontDestroyOnLoad(_escapeHandlerObj);
|
||||
}
|
||||
|
||||
scrController.instance!.StartCoroutine(SetupPlay());
|
||||
}
|
||||
|
||||
@@ -103,10 +112,8 @@ namespace ADOFAIRenderer.Component
|
||||
if (!scrController.instance || scrController.instance.state == States.Fail || scrController.instance.state == States.Fail2)
|
||||
{
|
||||
RenderMod.IsRendering = RenderMod.IsCapturing = false;
|
||||
|
||||
Time.timeScale = 1f;
|
||||
scrConductor.currentPreset.inputOffset = _originalInputOffset;
|
||||
StopFFmpeg(false);
|
||||
EndRender();
|
||||
}
|
||||
else if (scrController.instance.state == States.Won)
|
||||
{
|
||||
@@ -119,8 +126,6 @@ namespace ADOFAIRenderer.Component
|
||||
|
||||
if (FrameCount - WonFrame < extraFrames) return;
|
||||
RenderMod.IsRendering = RenderMod.IsCapturing = false;
|
||||
Time.timeScale = 1f;
|
||||
scrConductor.currentPreset.inputOffset = _originalInputOffset;
|
||||
StopFFmpeg(true);
|
||||
}
|
||||
}
|
||||
@@ -236,6 +241,7 @@ namespace ADOFAIRenderer.Component
|
||||
|
||||
var startTime = DateTime.Now;
|
||||
var fileName = startTime.ToString("yyyy-MM-dd HH-mm-ss") + ext;
|
||||
_currentOutPath = Path.Combine(MelonEnvironment.GameRootDirectory, "Render", fileName);
|
||||
|
||||
RenderThread = new Thread(() =>
|
||||
{
|
||||
@@ -244,10 +250,9 @@ namespace ADOFAIRenderer.Component
|
||||
var workingFps = (float)(targetFps % videoFps == 0.0 ? videoFps : targetFps);
|
||||
var videoFFmpeg = new VideoFFmpeg(Configuration.RenderWidth, Configuration.RenderHeight, (int)workingFps, (int)videoFps, selectedCodec);
|
||||
|
||||
var outPath = Path.Combine(MelonEnvironment.GameRootDirectory, "Render", fileName);
|
||||
SetupCaptureDirectory();
|
||||
|
||||
videoFFmpeg.Start(outPath, bitrate);
|
||||
videoFFmpeg.Start(_currentOutPath, bitrate);
|
||||
|
||||
int num = targetFps % videoFps != 0.0 ? 1 : (int)(targetFps / videoFps);
|
||||
|
||||
@@ -304,32 +309,100 @@ namespace ADOFAIRenderer.Component
|
||||
RenderThread.Start();
|
||||
}
|
||||
|
||||
public void CancelRender()
|
||||
{
|
||||
RenderMod.IsRendering = RenderMod.IsCapturing = false;
|
||||
StopFFmpeg(false);
|
||||
EndRender();
|
||||
}
|
||||
|
||||
private void StopFFmpeg(bool success)
|
||||
{
|
||||
EndRequested = true;
|
||||
SkipPressToStart = false;
|
||||
_renderSetup = false;
|
||||
if (_escapeHandlerObj)
|
||||
{
|
||||
Destroy(_escapeHandlerObj);
|
||||
_escapeHandlerObj = null;
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
StartCoroutine(StopRenderCoroutine());
|
||||
}
|
||||
else
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error("렌더링이 실패했거나 취소되었습니다.");
|
||||
Melon<RenderMod>.Logger.Error("렌더링이 실패했거나 취소되었습니다. 상태 및 리소스를 안전하게 청소합니다.");
|
||||
|
||||
// 1. 메모리 누수 방지: 큐에 렌트된 임시 프레임 버퍼 풀 반환 및 클리어
|
||||
lock (ImageQueue)
|
||||
{
|
||||
foreach (var kvp in ImageQueue)
|
||||
{
|
||||
if (kvp.Value != null && kvp.Value.Length > 0)
|
||||
{
|
||||
System.Buffers.ArrayPool<byte>.Shared.Return(kvp.Value);
|
||||
}
|
||||
}
|
||||
ImageQueue.Clear();
|
||||
}
|
||||
|
||||
// 디버그 모니터 UI 정리
|
||||
if (_debugMonitorObj)
|
||||
{
|
||||
Destroy(_debugMonitorObj);
|
||||
_debugMonitorObj = null;
|
||||
}
|
||||
|
||||
// 2. 렌더링 스레드가 큐 비어 있음을 감지하고 break 하도록 대기
|
||||
if (RenderThread is { IsAlive: true })
|
||||
{
|
||||
RenderThread.Join(2000);
|
||||
}
|
||||
|
||||
// 3. 인게임 카메라 및 렌더링용 RTCam 상태 안전 원복
|
||||
if (scrCamera.instance)
|
||||
{
|
||||
scrCamera.instance.forceRTCam = false;
|
||||
scrCamera.instance.SetupRTCam(false);
|
||||
|
||||
var hook = scrCamera.instance.GetComponent<PostRenderHook>();
|
||||
if (hook) Destroy(hook);
|
||||
}
|
||||
|
||||
// 4. 인게임 실패 방지 플래그 원상 복구
|
||||
if (scrController.instance)
|
||||
{
|
||||
scrController.instance.noFail = false;
|
||||
scrController.instance.noFailInfiniteMargin = false;
|
||||
}
|
||||
|
||||
// 5. 취소된 미완성 임시 동영상 파일 즉각 삭제
|
||||
if (!string.IsNullOrEmpty(_currentOutPath) && File.Exists(_currentOutPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(_currentOutPath);
|
||||
Melon<RenderMod>.Logger.Msg($"[File Cleanup] 미완성 동영상 삭제 완료: {_currentOutPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error($"[File Cleanup] 임시 동영상 삭제 실패: {ex.Message}");
|
||||
}
|
||||
_currentOutPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerator StopRenderCoroutine()
|
||||
{
|
||||
yield return new WaitUntil(() => EndSuccessful);
|
||||
EndRender();
|
||||
}
|
||||
|
||||
private static void EndRender()
|
||||
{
|
||||
Time.timeScale = 1f;
|
||||
if (_debugMonitorObj)
|
||||
{
|
||||
Destroy(_debugMonitorObj);
|
||||
@@ -337,6 +410,10 @@ namespace ADOFAIRenderer.Component
|
||||
}
|
||||
|
||||
RDC.auto = false;
|
||||
scrConductor.currentPreset.inputOffset = _originalInputOffset;
|
||||
GCS.customLevelPaths = null;
|
||||
GCS.customLevelId = null;
|
||||
|
||||
ADOBase.loader.LoadSceneWithTransition(WipeDirection.StartsFromRight, "scnEditor");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user