중간저장 04.20
This commit is contained in:
@@ -119,6 +119,35 @@ if (args.Length > 0 && string.Equals(args[0], "--inspect-tscn-folder", StringCom
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length > 0 && string.Equals(args[0], "--save-scene-image", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var saveImageOptions = SaveSceneImageOptions.Parse(args[1..]);
|
||||
Console.WriteLine(
|
||||
$"Karisma scene image save starting. target={saveImageOptions.Connection.Host}:{saveImageOptions.Connection.Port} " +
|
||||
$"scene={saveImageOptions.ScenePath} output={saveImageOptions.OutputPath} size={saveImageOptions.Width}x{saveImageOptions.Height} frame={saveImageOptions.Frame}");
|
||||
var saveImageResult = await SaveSceneImageAsync(saveImageOptions).ConfigureAwait(false);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Summary");
|
||||
Console.WriteLine($"- SDK Connect(): {(saveImageResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
||||
Console.WriteLine($"- Scene Load: {saveImageResult.SceneLoadOutcome}");
|
||||
Console.WriteLine($"- Save Scene Image: {saveImageResult.SaveOutcome}");
|
||||
Console.WriteLine($"- Output: {saveImageResult.OutputPath}");
|
||||
Console.WriteLine($"- Detail: {saveImageResult.Detail}");
|
||||
Environment.ExitCode = saveImageResult.ConnectRequestAccepted &&
|
||||
saveImageResult.SceneLoadOutcome == "SUCCESS" &&
|
||||
saveImageResult.SaveOutcome == "SUCCESS"
|
||||
? 0
|
||||
: 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length > 0 && string.Equals(args[0], "--validate-live-cuts", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Environment.ExitCode = await LiveCutValidation.RunAsync(args[1..]).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var options = ProbeOptions.Parse(args);
|
||||
|
||||
Console.WriteLine($"Karisma TCP probe starting. target={options.Host}:{options.Port} timeout={options.Timeout.TotalSeconds:0}s");
|
||||
@@ -321,6 +350,152 @@ static Task<CounterProbeResult> ProbeCounterAsync(CounterProbeOptions options)
|
||||
return completion.Task;
|
||||
}
|
||||
|
||||
static Task<SaveSceneImageProbeResult> SaveSceneImageAsync(SaveSceneImageOptions options)
|
||||
{
|
||||
var completion = new TaskCompletionSource<SaveSceneImageProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
ProbeEventHandler? handler = null;
|
||||
IKAEngine? engine = null;
|
||||
IKAScene? scene = null;
|
||||
try
|
||||
{
|
||||
handler = new ProbeEventHandler();
|
||||
engine = (IKAEngine)new KAEngineClass();
|
||||
|
||||
Console.WriteLine("[SAVE-IMAGE] Calling Connect()...");
|
||||
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
||||
Console.WriteLine($"[SAVE-IMAGE] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
||||
if (connectRequested == 0)
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(false, "NOT_RUN", "NOT_RUN", options.OutputPath, "Connect() returned 0."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(true, "NOT_RUN", "TIMEOUT", options.OutputPath, "OnConnect timed out."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler.ConnectTask.Result != 0)
|
||||
{
|
||||
completion.TrySetResult(
|
||||
new SaveSceneImageProbeResult(true, "NOT_RUN", "FAILED", options.OutputPath, $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("[SAVE-IMAGE] Loading scene...");
|
||||
handler.ResetLoadSceneTask();
|
||||
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
||||
if (scene is null)
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(true, "FAILED", "NOT_RUN", options.OutputPath, "LoadScene returned null."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(true, "TIMEOUT", "NOT_RUN", options.OutputPath, "OnLoadScene timed out."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
||||
{
|
||||
completion.TrySetResult(
|
||||
new SaveSceneImageProbeResult(true, handler.LoadSceneTask.Result.ToString(), "NOT_RUN", options.OutputPath, $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
||||
return;
|
||||
}
|
||||
|
||||
var outputDirectory = Path.GetDirectoryName(options.OutputPath);
|
||||
if (!string.IsNullOrWhiteSpace(outputDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
if (File.Exists(options.OutputPath))
|
||||
{
|
||||
File.Delete(options.OutputPath);
|
||||
}
|
||||
|
||||
Console.WriteLine("[SAVE-IMAGE] Calling SaveSceneImage()...");
|
||||
handler.ResetSaveSceneImageTask();
|
||||
scene.SaveSceneImage(options.OutputPath, options.Width, options.Height, options.Frame);
|
||||
|
||||
if (!WaitForTaskWithMessagePump(handler.SaveSceneImageTask, options.Connection.Timeout))
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, "OnSaveSceneImage timed out."));
|
||||
return;
|
||||
}
|
||||
|
||||
var saveResult = handler.SaveSceneImageTask.Result;
|
||||
if (saveResult != eKResult.RESULT_SUCCESS)
|
||||
{
|
||||
completion.TrySetResult(
|
||||
new SaveSceneImageProbeResult(true, "SUCCESS", saveResult.ToString(), options.OutputPath, $"OnSaveSceneImage result={saveResult}"));
|
||||
return;
|
||||
}
|
||||
|
||||
var fileWaitDeadline = DateTime.UtcNow + options.Connection.Timeout;
|
||||
while (DateTime.UtcNow < fileWaitDeadline)
|
||||
{
|
||||
if (File.Exists(options.OutputPath))
|
||||
{
|
||||
var info = new FileInfo(options.OutputPath);
|
||||
if (info.Length > 0)
|
||||
{
|
||||
completion.TrySetResult(
|
||||
new SaveSceneImageProbeResult(true, "SUCCESS", "SUCCESS", options.OutputPath, $"Saved {info.Length} bytes."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, "Image file was not created."));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completion.TrySetResult(new SaveSceneImageProbeResult(false, "EXCEPTION", "EXCEPTION", options.OutputPath, ex.ToString()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (scene is not null && handler is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (engine is not null && handler is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Disconnect();
|
||||
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "KarismaSaveSceneImageProbe"
|
||||
};
|
||||
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
return completion.Task;
|
||||
}
|
||||
|
||||
static Task<SceneCatalogProbeResult> CatalogScenesAsync(SceneCatalogOptions options)
|
||||
{
|
||||
var completion = new TaskCompletionSource<SceneCatalogProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
@@ -1381,6 +1556,70 @@ internal sealed record CounterProbeOptions(
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record SaveSceneImageOptions(
|
||||
ProbeOptions Connection,
|
||||
string ScenePath,
|
||||
string SceneAlias,
|
||||
string OutputPath,
|
||||
int Width,
|
||||
int Height,
|
||||
int Frame)
|
||||
{
|
||||
public static SaveSceneImageOptions Parse(string[] args)
|
||||
{
|
||||
var connection = ProbeOptions.Parse(args);
|
||||
string? scenePath = null;
|
||||
string? sceneAlias = null;
|
||||
string? outputPath = null;
|
||||
var width = 320;
|
||||
var height = 180;
|
||||
var frame = -1;
|
||||
|
||||
for (var index = 0; index < args.Length; index++)
|
||||
{
|
||||
switch (args[index])
|
||||
{
|
||||
case "--scene" when index + 1 < args.Length:
|
||||
scenePath = args[++index];
|
||||
break;
|
||||
case "--alias" when index + 1 < args.Length:
|
||||
sceneAlias = args[++index];
|
||||
break;
|
||||
case "--output" when index + 1 < args.Length:
|
||||
outputPath = args[++index];
|
||||
break;
|
||||
case "--width" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedWidth):
|
||||
width = parsedWidth;
|
||||
index++;
|
||||
break;
|
||||
case "--height" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedHeight):
|
||||
height = parsedHeight;
|
||||
index++;
|
||||
break;
|
||||
case "--frame" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedFrame):
|
||||
frame = parsedFrame;
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(scenePath))
|
||||
{
|
||||
throw new ArgumentException("--scene is required.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(outputPath))
|
||||
{
|
||||
throw new ArgumentException("--output is required.");
|
||||
}
|
||||
|
||||
scenePath = Path.GetFullPath(scenePath);
|
||||
outputPath = Path.GetFullPath(outputPath);
|
||||
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
||||
return new SaveSceneImageOptions(connection, scenePath, sceneAlias, outputPath, width, height, frame);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record SceneCatalogOptions(
|
||||
ProbeOptions Connection,
|
||||
string RootPath,
|
||||
@@ -1531,6 +1770,7 @@ internal sealed record FolderInspectionOptions(ProbeOptions Connection, string R
|
||||
|
||||
internal sealed record SdkProbeResult(bool ConnectRequestAccepted, string ConnectOutcome, string Detail);
|
||||
internal sealed record CounterProbeResult(bool ConnectRequestAccepted, string SceneLoadOutcome, string CounterOutcome, string Detail);
|
||||
internal sealed record SaveSceneImageProbeResult(bool ConnectRequestAccepted, string SceneLoadOutcome, string SaveOutcome, string OutputPath, string Detail);
|
||||
internal sealed record SceneCatalogProbeResult(
|
||||
bool ConnectRequestAccepted,
|
||||
int SceneCount,
|
||||
@@ -1597,6 +1837,7 @@ internal sealed class ProbeEventHandler : KAEventHandler
|
||||
private TaskCompletionSource<eKResult> _styleColorTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private TaskCompletionSource<eKResult> _visibleTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private TaskCompletionSource<eKResult> _setValueTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private TaskCompletionSource<eKResult> _saveSceneImageTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private TaskCompletionSource<ObjectInfosProbeResult> _objectInfosTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private IKAScene? _sceneToQueryOnLoad;
|
||||
|
||||
@@ -1616,6 +1857,8 @@ internal sealed class ProbeEventHandler : KAEventHandler
|
||||
|
||||
public Task<eKResult> SetValueTask => _setValueTask.Task;
|
||||
|
||||
public Task<eKResult> SaveSceneImageTask => _saveSceneImageTask.Task;
|
||||
|
||||
public Task<ObjectInfosProbeResult> ObjectInfosTask => _objectInfosTask.Task;
|
||||
|
||||
public void ResetLoadSceneTask() => _loadSceneTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
@@ -1630,6 +1873,8 @@ internal sealed class ProbeEventHandler : KAEventHandler
|
||||
|
||||
public void ResetSetValueTask() => _setValueTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public void ResetSaveSceneImageTask() => _saveSceneImageTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public void ResetObjectInfosTask() => _objectInfosTask = new TaskCompletionSource<ObjectInfosProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public void ConfigureQueryObjectInfosOnLoad(IKAScene scene) => _sceneToQueryOnLoad = scene;
|
||||
@@ -1717,7 +1962,11 @@ internal sealed class ProbeEventHandler : KAEventHandler
|
||||
public void OnSetBackgroundVideoPlayInfo(eKResult Result, string SceneName) { }
|
||||
public void OnQueryBackgroundVideoPlayInfo(eKResult Result, string SceneName, ref sKVideoPlayInfo pVideoPlayInfo) { }
|
||||
public void OnSetSceneEffectType(eKResult Result, string SceneName) { }
|
||||
public void OnSaveSceneImage(eKResult Result, string SceneName) { }
|
||||
public void OnSaveSceneImage(eKResult Result, string SceneName)
|
||||
{
|
||||
Console.WriteLine($"[SDK] OnSaveSceneImage result={Result} scene={SceneName}");
|
||||
_saveSceneImageTask.TrySetResult(Result);
|
||||
}
|
||||
public void OnSaveScene(eKResult Result, string SceneName) { }
|
||||
public void OnUnloadScene(eKResult Result, string SceneName)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user