5249 lines
223 KiB
C#
5249 lines
223 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using KAsyncEngineLib;
|
|
using Tornado3_2026Election.Services;
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--reflect-api", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
PrintApiSurface();
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--test-counter", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var counterOptions = CounterProbeOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma counter probe starting. target={counterOptions.Connection.Host}:{counterOptions.Connection.Port} " +
|
|
$"scene={counterOptions.ScenePath} object={counterOptions.ObjectName} keyIndex={counterOptions.KeyIndex} value={counterOptions.Number:0.###}");
|
|
var counterResult = await ProbeCounterAsync(counterOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(counterResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {counterResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Counter Update: {counterResult.CounterOutcome}");
|
|
Console.WriteLine($"- Detail: {counterResult.Detail}");
|
|
Environment.ExitCode = counterResult.ConnectRequestAccepted &&
|
|
counterResult.SceneLoadOutcome == "SUCCESS" &&
|
|
counterResult.CounterOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--inspect-chart", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var chartOptions = ChartInspectionOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma chart inspection starting. target={chartOptions.Connection.Host}:{chartOptions.Connection.Port} " +
|
|
$"scene={chartOptions.ScenePath} object={chartOptions.ObjectName}");
|
|
var chartResult = await InspectChartAsync(chartOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(chartResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {chartResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Chart Inspection: {chartResult.InspectionOutcome}");
|
|
Console.WriteLine($"- Rows: {chartResult.RowCount}");
|
|
Console.WriteLine($"- Columns: {chartResult.ColumnCount}");
|
|
if (chartResult.Cells.Count > 0)
|
|
{
|
|
Console.WriteLine("- Cells:");
|
|
foreach (var cell in chartResult.Cells)
|
|
{
|
|
Console.WriteLine($" - ({cell.Row},{cell.Column}) = {cell.Value}");
|
|
}
|
|
}
|
|
Console.WriteLine($"- Detail: {chartResult.Detail}");
|
|
Environment.ExitCode = chartResult.ConnectRequestAccepted &&
|
|
chartResult.SceneLoadOutcome == "SUCCESS" &&
|
|
chartResult.InspectionOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--catalog-scenes", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var catalogOptions = SceneCatalogOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma scene catalog starting. target={catalogOptions.Connection.Host}:{catalogOptions.Connection.Port} " +
|
|
$"root={catalogOptions.RootPath} output={catalogOptions.OutputPath}");
|
|
var catalogResult = await CatalogScenesAsync(catalogOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(catalogResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scenes Found: {catalogResult.SceneCount}");
|
|
Console.WriteLine($"- Scenes Cataloged: {catalogResult.CatalogedCount}");
|
|
Console.WriteLine($"- Failures: {catalogResult.Failures.Count}");
|
|
Console.WriteLine($"- Output: {catalogResult.OutputPath}");
|
|
if (catalogResult.Failures.Count > 0)
|
|
{
|
|
Console.WriteLine("- Failure Details:");
|
|
foreach (var failure in catalogResult.Failures.Take(20))
|
|
{
|
|
Console.WriteLine($" - {failure.ScenePath}: {failure.Reason}");
|
|
}
|
|
}
|
|
|
|
Environment.ExitCode = catalogResult.ConnectRequestAccepted && catalogResult.Failures.Count == 0
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--inspect-scene-objects", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var inspectionOptions = SceneObjectInspectionOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma scene object inspection starting. target={inspectionOptions.Connection.Host}:{inspectionOptions.Connection.Port} " +
|
|
$"scene={inspectionOptions.ScenePath} output={inspectionOptions.OutputPath}");
|
|
var inspectionResult = await InspectSceneObjectsAsync(inspectionOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(inspectionResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {inspectionResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Object Infos: {inspectionResult.ObjectInfoOutcome}");
|
|
Console.WriteLine($"- Objects: {inspectionResult.Objects.Count}");
|
|
Console.WriteLine($"- Output: {inspectionResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(inspectionResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {inspectionResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = inspectionResult.ConnectRequestAccepted &&
|
|
inspectionResult.SceneLoadOutcome == "SUCCESS" &&
|
|
inspectionResult.ObjectInfoOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--query-object-types", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var objectTypeOptions = ObjectTypeQueryOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma object type query starting. target={objectTypeOptions.Connection.Host}:{objectTypeOptions.Connection.Port} " +
|
|
$"scene={objectTypeOptions.ScenePath} objects={objectTypeOptions.ObjectNames.Count}");
|
|
var objectTypeResult = await QueryObjectTypesAsync(objectTypeOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(objectTypeResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {objectTypeResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Queried: {objectTypeResult.Items.Count}");
|
|
Console.WriteLine($"- Output: {objectTypeResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(objectTypeResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {objectTypeResult.Detail}");
|
|
}
|
|
|
|
foreach (var item in objectTypeResult.Items)
|
|
{
|
|
Console.WriteLine($" - {item.ObjectName}: {item.Result} {item.ObjectType}");
|
|
}
|
|
|
|
Environment.ExitCode = objectTypeResult.ConnectRequestAccepted &&
|
|
objectTypeResult.SceneLoadOutcome == "SUCCESS" &&
|
|
objectTypeResult.Items.All(item => string.Equals(item.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal))
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--inspect-object-runtime", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var runtimeOptions = ObjectTypeQueryOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma object runtime inspection starting. target={runtimeOptions.Connection.Host}:{runtimeOptions.Connection.Port} " +
|
|
$"scene={runtimeOptions.ScenePath} objects={runtimeOptions.ObjectNames.Count} output={runtimeOptions.OutputPath}");
|
|
var runtimeResult = await InspectObjectRuntimeAsync(runtimeOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(runtimeResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {runtimeResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Objects Inspected: {runtimeResult.Items.Count}");
|
|
Console.WriteLine($"- Output: {runtimeResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(runtimeResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {runtimeResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = runtimeResult.ConnectRequestAccepted &&
|
|
runtimeResult.SceneLoadOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--query-objects-by-screen-point", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var screenPointOptions = ScreenPointInspectionOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma screen-point inspection starting. target={screenPointOptions.Connection.Host}:{screenPointOptions.Connection.Port} " +
|
|
$"scene={screenPointOptions.ScenePath} points={screenPointOptions.Points.Count} output={screenPointOptions.OutputPath}");
|
|
var screenPointResult = await InspectScreenPointsAsync(screenPointOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(screenPointResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {screenPointResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Points Inspected: {screenPointResult.Items.Count}");
|
|
Console.WriteLine($"- Output: {screenPointResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(screenPointResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {screenPointResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = screenPointResult.ConnectRequestAccepted &&
|
|
screenPointResult.SceneLoadOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--inspect-scene-capabilities", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var capabilityOptions = SceneCapabilityInspectionOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma scene capability inspection starting. target={capabilityOptions.Connection.Host}:{capabilityOptions.Connection.Port} " +
|
|
$"scene={capabilityOptions.ScenePath} output={capabilityOptions.OutputPath}");
|
|
var capabilityResult = await InspectSceneCapabilitiesAsync(capabilityOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(capabilityResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {capabilityResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Candidates Inspected: {capabilityResult.Items.Count}");
|
|
Console.WriteLine($"- Output: {capabilityResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(capabilityResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {capabilityResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = capabilityResult.ConnectRequestAccepted &&
|
|
capabilityResult.SceneLoadOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--validate-scene-values", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var validationOptions = SceneValidationOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma scene validation starting. target={validationOptions.Connection.Host}:{validationOptions.Connection.Port} " +
|
|
$"scene={validationOptions.ScenePath} ops={validationOptions.OperationsPath} output={validationOptions.OutputPath}");
|
|
var validationResult = await ValidateSceneOperationsAsync(validationOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(validationResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scene Load: {validationResult.SceneLoadOutcome}");
|
|
Console.WriteLine($"- Success Count: {validationResult.SuccessCount}");
|
|
Console.WriteLine($"- Failure Count: {validationResult.FailureCount}");
|
|
Console.WriteLine($"- Output: {validationResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(validationResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {validationResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = validationResult.ConnectRequestAccepted &&
|
|
validationResult.SceneLoadOutcome == "SUCCESS" &&
|
|
validationResult.FailureCount == 0
|
|
? 0
|
|
: 1;
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--inspect-tscn-folder", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var inspectionOptions = FolderInspectionOptions.Parse(args[1..]);
|
|
Console.WriteLine(
|
|
$"Karisma tscn inspection starting. target={inspectionOptions.Connection.Host}:{inspectionOptions.Connection.Port} " +
|
|
$"root={inspectionOptions.RootPath} output={inspectionOptions.OutputPath}");
|
|
var inspectionResult = await InspectTscnFolderAsync(inspectionOptions).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- SDK Connect(): {(inspectionResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- Scenes Found: {inspectionResult.SceneCount}");
|
|
Console.WriteLine($"- Scenes Processed: {inspectionResult.ProcessedSceneCount}");
|
|
Console.WriteLine($"- Variables Found: {inspectionResult.DiscoveredVariableCount}");
|
|
Console.WriteLine($"- Failures: {inspectionResult.FailureCount}");
|
|
Console.WriteLine($"- Output: {inspectionResult.OutputPath}");
|
|
if (!string.IsNullOrWhiteSpace(inspectionResult.Detail))
|
|
{
|
|
Console.WriteLine($"- Detail: {inspectionResult.Detail}");
|
|
}
|
|
|
|
Environment.ExitCode = inspectionResult.ConnectRequestAccepted && inspectionResult.FailureCount == 0
|
|
? 0
|
|
: 1;
|
|
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;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--audit-party-colors-live", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Environment.ExitCode = await LiveCutValidation.RunPartyColorAuditAsync(args[1..]).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--validate-current-api-cuts", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Environment.ExitCode = await CurrentApiCutDiagnostics.RunAsync(args[1..]).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--sweep-cut-debug", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Environment.ExitCode = await LiveCutValidation.RunCutDebugSweepAsync(args[1..]).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--report-cut-debug-coverage", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Environment.ExitCode = LiveCutValidation.RunCutDebugCoverageReport(args[1..]);
|
|
return;
|
|
}
|
|
|
|
if (args.Length > 0 && string.Equals(args[0], "--audit-cut-files", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Environment.ExitCode = await CutFileAudit.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");
|
|
|
|
var rawTcpOk = await ProbeRawTcpAsync(options).ConfigureAwait(false);
|
|
var sdkResult = await ProbeSdkAsync(options).ConfigureAwait(false);
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Summary");
|
|
Console.WriteLine($"- Raw TCP: {(rawTcpOk ? "OK" : "FAILED")}");
|
|
Console.WriteLine($"- SDK Connect(): {(sdkResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}");
|
|
Console.WriteLine($"- SDK OnConnect: {sdkResult.ConnectOutcome}");
|
|
Console.WriteLine($"- SDK Detail: {sdkResult.Detail}");
|
|
|
|
Environment.ExitCode = rawTcpOk && sdkResult.ConnectRequestAccepted && sdkResult.ConnectOutcome == "SUCCESS"
|
|
? 0
|
|
: 1;
|
|
|
|
static void PrintApiSurface()
|
|
{
|
|
PrintTypeMethods(typeof(IKAObject));
|
|
PrintTypeMethods(typeof(KAObject));
|
|
PrintTypeMethods(typeof(IKAScene));
|
|
PrintTypeMethods(typeof(KAScene));
|
|
PrintTypeMethods(typeof(IKAEngine));
|
|
PrintTypeMethods(typeof(KAEngine));
|
|
PrintTypeMethods(typeof(IKACounter));
|
|
PrintTypeMethods(typeof(KACounter));
|
|
PrintTypeMethods(typeof(IKAObjectInfos));
|
|
PrintTypeMethods(typeof(KAObjectInfos));
|
|
PrintStructFields(typeof(sKObjectInfo));
|
|
PrintEnumValues(typeof(eKObjectType));
|
|
}
|
|
|
|
static void PrintTypeMethods(Type type)
|
|
{
|
|
Console.WriteLine(type.FullName);
|
|
foreach (var method in type.GetMethods())
|
|
{
|
|
if (!method.Name.Contains("Counter", StringComparison.OrdinalIgnoreCase) &&
|
|
!string.Equals(method.Name, "SetValue", StringComparison.OrdinalIgnoreCase) &&
|
|
!method.Name.Contains("GetObject", StringComparison.OrdinalIgnoreCase) &&
|
|
!method.Name.Contains("QueryObjectInfos", StringComparison.OrdinalIgnoreCase) &&
|
|
!method.Name.Contains("GetCount", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var parameters = string.Join(
|
|
", ",
|
|
method.GetParameters().Select(parameter => $"{parameter.ParameterType.Name} {parameter.Name}"));
|
|
Console.WriteLine($"- {method.ReturnType.Name} {method.Name}({parameters})");
|
|
}
|
|
|
|
Console.WriteLine();
|
|
}
|
|
|
|
static void PrintStructFields(Type type)
|
|
{
|
|
Console.WriteLine(type.FullName);
|
|
foreach (var field in type.GetFields())
|
|
{
|
|
Console.WriteLine($"- {field.FieldType.Name} {field.Name}");
|
|
}
|
|
|
|
Console.WriteLine();
|
|
}
|
|
|
|
static void PrintEnumValues(Type type)
|
|
{
|
|
Console.WriteLine(type.FullName);
|
|
foreach (var name in Enum.GetNames(type))
|
|
{
|
|
Console.WriteLine($"- {name}");
|
|
}
|
|
|
|
Console.WriteLine();
|
|
}
|
|
|
|
static async Task<bool> ProbeRawTcpAsync(ProbeOptions options)
|
|
{
|
|
try
|
|
{
|
|
using var client = new TcpClient();
|
|
using var cts = new CancellationTokenSource(options.Timeout);
|
|
await client.ConnectAsync(options.Host, options.Port, cts.Token).ConfigureAwait(false);
|
|
Console.WriteLine($"[RAW] Connected local={client.Client.LocalEndPoint} remote={client.Client.RemoteEndPoint}");
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[RAW] Failed: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Task<CounterProbeResult> ProbeCounterAsync(CounterProbeOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<CounterProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
try
|
|
{
|
|
var handler = new ProbeEventHandler();
|
|
var engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[COUNTER] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[COUNTER] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new CounterProbeResult(false, "NOT_RUN", "NOT_RUN", "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new CounterProbeResult(true, "NOT_RUN", "TIMEOUT", "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new CounterProbeResult(true, "NOT_RUN", "FAILED", $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[COUNTER] Loading scene...");
|
|
var scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(new CounterProbeResult(true, "FAILED", "NOT_RUN", "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new CounterProbeResult(true, "TIMEOUT", "NOT_RUN", "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
var loadSceneResult = handler.LoadSceneTask.Result;
|
|
if (loadSceneResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new CounterProbeResult(true, loadSceneResult.ToString(), "NOT_RUN", $"OnLoadScene result={loadSceneResult}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[COUNTER] Resolving object...");
|
|
var sceneObject = scene.GetObject(options.ObjectName);
|
|
if (sceneObject is not IKACounter counter)
|
|
{
|
|
completion.TrySetResult(
|
|
new CounterProbeResult(true, "SUCCESS", "FAILED", $"Object '{options.ObjectName}' is not an IKACounter."));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[COUNTER] Calling SetCounterNumberKey()...");
|
|
counter.SetCounterNumberKey(options.KeyIndex, options.Number);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new CounterProbeResult(true, "SUCCESS", "TIMEOUT", "OnSetCounterNumberKey timed out."));
|
|
return;
|
|
}
|
|
|
|
var counterResult = handler.CounterNumberKeyTask.Result;
|
|
completion.TrySetResult(
|
|
new CounterProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
counterResult == eKResult.RESULT_SUCCESS ? "SUCCESS" : counterResult.ToString(),
|
|
$"OnSetCounterNumberKey result={counterResult}"));
|
|
|
|
try
|
|
{
|
|
engine.Disconnect();
|
|
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new CounterProbeResult(false, "EXCEPTION", "EXCEPTION", ex.ToString()));
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "KarismaCounterProbe"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<ChartInspectionProbeResult> InspectChartAsync(ChartInspectionOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<ChartInspectionProbeResult>(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("[CHART] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[CHART] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new ChartInspectionProbeResult(false, "NOT_RUN", "NOT_RUN", 0, 0, Array.Empty<ChartCellSnapshot>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new ChartInspectionProbeResult(true, "NOT_RUN", "TIMEOUT", 0, 0, Array.Empty<ChartCellSnapshot>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ChartInspectionProbeResult(true, "NOT_RUN", "FAILED", 0, 0, Array.Empty<ChartCellSnapshot>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[CHART] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(new ChartInspectionProbeResult(true, "FAILED", "NOT_RUN", 0, 0, Array.Empty<ChartCellSnapshot>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new ChartInspectionProbeResult(true, "TIMEOUT", "NOT_RUN", 0, 0, Array.Empty<ChartCellSnapshot>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
var loadSceneResult = handler.LoadSceneTask.Result;
|
|
if (loadSceneResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new ChartInspectionProbeResult(true, loadSceneResult.ToString(), "NOT_RUN", 0, 0, Array.Empty<ChartCellSnapshot>(), $"OnLoadScene result={loadSceneResult}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[CHART] Resolving object...");
|
|
var sceneObject = scene.GetObject(options.ObjectName);
|
|
if (sceneObject is not IKAChart chart)
|
|
{
|
|
completion.TrySetResult(
|
|
new ChartInspectionProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
"FAILED",
|
|
0,
|
|
0,
|
|
Array.Empty<ChartCellSnapshot>(),
|
|
sceneObject is null
|
|
? $"Object '{options.ObjectName}' was not found."
|
|
: $"Object '{options.ObjectName}' is not an IKAChart ({sceneObject.GetType().FullName})."));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[CHART] Calling QueryChartDataTable()...");
|
|
handler.ResetChartDataTableTask();
|
|
chart.QueryChartDataTable();
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ChartDataTableTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ChartInspectionProbeResult(true, "SUCCESS", "TIMEOUT", 0, 0, Array.Empty<ChartCellSnapshot>(), "OnQueryChartDataTable timed out."));
|
|
return;
|
|
}
|
|
|
|
var chartResult = handler.ChartDataTableTask.Result;
|
|
completion.TrySetResult(
|
|
new ChartInspectionProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
chartResult.Result == eKResult.RESULT_SUCCESS ? "SUCCESS" : chartResult.Result.ToString(),
|
|
chartResult.RowCount,
|
|
chartResult.ColumnCount,
|
|
chartResult.Cells,
|
|
string.IsNullOrWhiteSpace(chartResult.Detail)
|
|
? $"OnQueryChartDataTable result={chartResult.Result}"
|
|
: chartResult.Detail));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new ChartInspectionProbeResult(false, "EXCEPTION", "EXCEPTION", 0, 0, Array.Empty<ChartCellSnapshot>(), 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 = "KarismaChartInspectionProbe"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
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;
|
|
}
|
|
|
|
if (options.CloneObject is not null)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Adding clone source={options.CloneObject.SourceObjectName} " +
|
|
$"variable={options.CloneObject.VariableName}...");
|
|
var sceneObject = scene.GetObject(options.CloneObject.SourceObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.CloneObject.SourceObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetAddCloneObjectTask();
|
|
scene.AddCloneObject(sceneObject, options.CloneObject.VariableName);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.AddCloneObjectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnAddCloneObject timed out for '{options.CloneObject.SourceObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var cloneResult = handler.AddCloneObjectTask.Result;
|
|
if (cloneResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", cloneResult.ToString(), options.OutputPath, $"OnAddCloneObject result={cloneResult} source={options.CloneObject.SourceObjectName} variable={options.CloneObject.VariableName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (options.VariableName is not null)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting variable name object={options.VariableName.ObjectName} " +
|
|
$"value={options.VariableName.VariableName}...");
|
|
var sceneObject = scene.GetObject(options.VariableName.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.VariableName.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetVariableNameTask();
|
|
sceneObject.SetVariableName(options.VariableName.VariableName);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.VariableNameTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetVariableName timed out for '{options.VariableName.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var variableNameResult = handler.VariableNameTask.Result;
|
|
if (variableNameResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", variableNameResult.ToString(), options.OutputPath, $"OnSetVariableName result={variableNameResult} object={options.VariableName.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.SetObjectName))
|
|
{
|
|
Console.WriteLine($"[SAVE-IMAGE] Setting value object={options.SetObjectName}...");
|
|
var sceneObject = scene.GetObject(options.SetObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.SetObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetSetValueTask();
|
|
sceneObject.SetValue(options.SetObjectValue ?? string.Empty);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.SetValueTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetValue timed out for '{options.SetObjectName}'."));
|
|
return;
|
|
}
|
|
|
|
var setValueResult = handler.SetValueTask.Result;
|
|
if (setValueResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", setValueResult.ToString(), options.OutputPath, $"OnSetValue result={setValueResult} object={options.SetObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.VisibleObjectName) && options.VisibleObjectValue.HasValue)
|
|
{
|
|
Console.WriteLine($"[SAVE-IMAGE] Setting visibility object={options.VisibleObjectName} visible={options.VisibleObjectValue.Value}...");
|
|
var sceneObject = scene.GetObject(options.VisibleObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.VisibleObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetVisibleTask();
|
|
sceneObject.SetVisible(options.VisibleObjectValue.Value ? 1 : 0);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.VisibleTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetVisible timed out for '{options.VisibleObjectName}'."));
|
|
return;
|
|
}
|
|
|
|
var visibleResult = handler.VisibleTask.Result;
|
|
if (visibleResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", visibleResult.ToString(), options.OutputPath, $"OnSetVisible result={visibleResult} object={options.VisibleObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
IReadOnlyList<SceneValidationOperation> operations = string.IsNullOrWhiteSpace(options.OperationsPath)
|
|
? Array.Empty<SceneValidationOperation>()
|
|
: LoadSceneOperations(options.ScenePath, options.OperationsPath);
|
|
foreach (var operation in operations)
|
|
{
|
|
var operationResult = ApplySceneOperation(handler, scene!, operation, options.Connection.Timeout);
|
|
if (!string.Equals(operationResult.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal))
|
|
{
|
|
if (operation.ContinueOnFailure)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Optional operation {operationResult.Method} failed for '{operationResult.ObjectName}': " +
|
|
$"{operationResult.Result} {operationResult.Detail}");
|
|
continue;
|
|
}
|
|
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
operationResult.Result,
|
|
options.OutputPath,
|
|
$"Operation {operationResult.Method} failed for '{operationResult.ObjectName}': {operationResult.Detail}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (options.MaterialOpacity is not null)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting material opacity object={options.MaterialOpacity.ObjectName} " +
|
|
$"value={options.MaterialOpacity.Opacity}...");
|
|
var sceneObject = scene.GetObject(options.MaterialOpacity.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.MaterialOpacity.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
var material = sceneObject.GetTargetMaterial(eKMaterialTarget.MATERIAL_TARGET_DEFAULT);
|
|
if (material is not IKAMaterial targetMaterial)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.MaterialOpacity.ObjectName}' did not return a material."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetMaterialOpacityTask();
|
|
targetMaterial.SetTransparencyOpacity(options.MaterialOpacity.Opacity);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.MaterialOpacityTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetTransparencyOpacity timed out for '{options.MaterialOpacity.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var opacityResult = handler.MaterialOpacityTask.Result;
|
|
if (opacityResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", opacityResult.ToString(), options.OutputPath, $"OnSetTransparencyOpacity result={opacityResult} object={options.MaterialOpacity.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (options.Size is not null)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting size object={options.Size.ObjectName} value=({options.Size.Width},{options.Size.Height})...");
|
|
var sceneObject = scene.GetObject(options.Size.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{options.Size.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetSizeTask();
|
|
sceneObject.SetSize(options.Size.Width, options.Size.Height);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.SizeTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetSize timed out for '{options.Size.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var sizeResult = handler.SizeTask.Result;
|
|
if (sizeResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", sizeResult.ToString(), options.OutputPath, $"OnSetSize result={sizeResult} object={options.Size.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
var positionUpdates = new List<PositionUpdate>();
|
|
if (options.Position is not null)
|
|
{
|
|
positionUpdates.Add(options.Position);
|
|
}
|
|
|
|
positionUpdates.AddRange(options.Positions);
|
|
foreach (var positionUpdate in positionUpdates)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting position object={positionUpdate.ObjectName} " +
|
|
$"value=({positionUpdate.X},{positionUpdate.Y},{positionUpdate.Z}) vector={positionUpdate.VectorType}...");
|
|
var sceneObject = scene.GetObject(positionUpdate.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{positionUpdate.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetPositionTask();
|
|
sceneObject.SetPosition(
|
|
positionUpdate.X,
|
|
positionUpdate.Y,
|
|
positionUpdate.Z,
|
|
positionUpdate.VectorType);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PositionTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetPosition timed out for '{positionUpdate.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var positionResult = handler.PositionTask.Result;
|
|
if (positionResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", positionResult.ToString(), options.OutputPath, $"OnSetPosition result={positionResult} object={positionUpdate.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
var positionKeyUpdates = new List<PositionKeyUpdate>();
|
|
if (options.PositionKey is not null)
|
|
{
|
|
positionKeyUpdates.Add(options.PositionKey);
|
|
}
|
|
|
|
positionKeyUpdates.AddRange(options.PositionKeys);
|
|
foreach (var positionKeyUpdate in positionKeyUpdates)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting position key object={positionKeyUpdate.ObjectName} index={positionKeyUpdate.KeyIndex} " +
|
|
$"value=({positionKeyUpdate.X},{positionKeyUpdate.Y},{positionKeyUpdate.Z}) vector={positionKeyUpdate.VectorType}...");
|
|
var sceneObject = scene.GetObject(positionKeyUpdate.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{positionKeyUpdate.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetPositionKeyTask();
|
|
sceneObject.SetPositionKey(
|
|
positionKeyUpdate.KeyIndex,
|
|
positionKeyUpdate.X,
|
|
positionKeyUpdate.Y,
|
|
positionKeyUpdate.Z,
|
|
positionKeyUpdate.VectorType);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PositionKeyTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetPositionKey timed out for '{positionKeyUpdate.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var positionKeyResult = handler.PositionKeyTask.Result;
|
|
if (positionKeyResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", positionKeyResult.ToString(), options.OutputPath, $"OnSetPositionKey result={positionKeyResult} object={positionKeyUpdate.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.ChartObjectName))
|
|
{
|
|
var sceneObject = scene.GetObject(options.ChartObjectName);
|
|
if (sceneObject is not IKAChart chart)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
"FAILED",
|
|
options.OutputPath,
|
|
sceneObject is null
|
|
? $"Object '{options.ChartObjectName}' was not found."
|
|
: $"Object '{options.ChartObjectName}' does not implement IKAChart ({sceneObject.GetType().FullName})."));
|
|
return;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.ChartCsvPath))
|
|
{
|
|
Console.WriteLine($"[SAVE-IMAGE] Setting chart csv object={options.ChartObjectName} csv={options.ChartCsvPath}...");
|
|
handler.ResetChartMutationTask();
|
|
chart.SetChartCSVFile(options.ChartCsvPath);
|
|
if (!WaitForTaskWithMessagePump(handler.ChartMutationTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetChartCSVFile timed out for '{options.ChartObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
if (handler.ChartMutationTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", handler.ChartMutationTask.Result.ToString(), options.OutputPath, $"OnSetChartCSVFile result={handler.ChartMutationTask.Result} object={options.ChartObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach (var cell in options.ChartCells)
|
|
{
|
|
Console.WriteLine($"[SAVE-IMAGE] Setting chart cell object={options.ChartObjectName} row={cell.Row} col={cell.Column} value={cell.Value}...");
|
|
handler.ResetChartMutationTask();
|
|
chart.SetChartCellData(cell.Row, cell.Column, cell.Value);
|
|
if (!WaitForTaskWithMessagePump(handler.ChartMutationTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetChartCellData timed out for '{options.ChartObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
if (handler.ChartMutationTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", handler.ChartMutationTask.Result.ToString(), options.OutputPath, $"OnSetChartCellData result={handler.ChartMutationTask.Result} object={options.ChartObjectName} row={cell.Row} col={cell.Column}"));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.PathObjectName))
|
|
{
|
|
Console.WriteLine($"[SAVE-IMAGE] Rebuilding path object={options.PathObjectName}...");
|
|
var sceneObject = scene.GetObject(options.PathObjectName);
|
|
if (sceneObject is not IKAPath path)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
"FAILED",
|
|
options.OutputPath,
|
|
sceneObject is null
|
|
? $"Object '{options.PathObjectName}' was not found."
|
|
: $"Object '{options.PathObjectName}' does not implement IKAPath ({sceneObject.GetType().FullName})."));
|
|
return;
|
|
}
|
|
|
|
if (options.PathPoints.Count > 0)
|
|
{
|
|
handler.ResetPathPointTask();
|
|
path.ClearPathPoints();
|
|
if (!WaitForTaskWithMessagePump(handler.PathPointTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnClearPathPoints timed out for '{options.PathObjectName}'."));
|
|
return;
|
|
}
|
|
|
|
if (handler.PathPointTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", handler.PathPointTask.Result.ToString(), options.OutputPath, $"OnClearPathPoints result={handler.PathPointTask.Result} object={options.PathObjectName}"));
|
|
return;
|
|
}
|
|
|
|
foreach (var point in options.PathPoints)
|
|
{
|
|
handler.ResetPathPointTask();
|
|
path.AddPathPoint(point.X, point.Y, point.Z);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PathPointTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnAddPathPoint timed out for '{options.PathObjectName}'."));
|
|
return;
|
|
}
|
|
|
|
if (handler.PathPointTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", handler.PathPointTask.Result.ToString(), options.OutputPath, $"OnAddPathPoint result={handler.PathPointTask.Result} object={options.PathObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var modification in options.PathModifications)
|
|
{
|
|
handler.ResetPathPointTask();
|
|
path.ModifyPathPoint(
|
|
modification.Index,
|
|
modification.X,
|
|
modification.Y,
|
|
modification.Z,
|
|
modification.VectorType);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PathPointTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnModifyPathPoint timed out for '{options.PathObjectName}'."));
|
|
return;
|
|
}
|
|
|
|
if (handler.PathPointTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", handler.PathPointTask.Result.ToString(), options.OutputPath, $"OnModifyPathPoint result={handler.PathPointTask.Result} object={options.PathObjectName} index={modification.Index}"));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var positionUpdate in options.PostPositions)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting post-chart position object={positionUpdate.ObjectName} " +
|
|
$"value=({positionUpdate.X},{positionUpdate.Y},{positionUpdate.Z}) vector={positionUpdate.VectorType}...");
|
|
var sceneObject = scene.GetObject(positionUpdate.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{positionUpdate.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetPositionTask();
|
|
sceneObject.SetPosition(
|
|
positionUpdate.X,
|
|
positionUpdate.Y,
|
|
positionUpdate.Z,
|
|
positionUpdate.VectorType);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PositionTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetPosition timed out for '{positionUpdate.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var positionResult = handler.PositionTask.Result;
|
|
if (positionResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", positionResult.ToString(), options.OutputPath, $"OnSetPosition result={positionResult} object={positionUpdate.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach (var positionKeyUpdate in options.PostPositionKeys)
|
|
{
|
|
Console.WriteLine(
|
|
$"[SAVE-IMAGE] Setting post-chart position key object={positionKeyUpdate.ObjectName} index={positionKeyUpdate.KeyIndex} " +
|
|
$"value=({positionKeyUpdate.X},{positionKeyUpdate.Y},{positionKeyUpdate.Z}) vector={positionKeyUpdate.VectorType}...");
|
|
var sceneObject = scene.GetObject(positionKeyUpdate.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", options.OutputPath, $"Object '{positionKeyUpdate.ObjectName}' was not found."));
|
|
return;
|
|
}
|
|
|
|
handler.ResetPositionKeyTask();
|
|
sceneObject.SetPositionKey(
|
|
positionKeyUpdate.KeyIndex,
|
|
positionKeyUpdate.X,
|
|
positionKeyUpdate.Y,
|
|
positionKeyUpdate.Z,
|
|
positionKeyUpdate.VectorType);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.PositionKeyTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, $"OnSetPositionKey timed out for '{positionKeyUpdate.ObjectName}'." ));
|
|
return;
|
|
}
|
|
|
|
var positionKeyResult = handler.PositionKeyTask.Result;
|
|
if (positionKeyResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", positionKeyResult.ToString(), options.OutputPath, $"OnSetPositionKey result={positionKeyResult} object={positionKeyUpdate.ObjectName}"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
var captures = new List<(string OutputPath, int Frame)>();
|
|
if (options.Frames.Count > 0)
|
|
{
|
|
var captureDirectory = options.OutputDirectory ?? options.OutputPath;
|
|
foreach (var captureFrame in options.Frames)
|
|
{
|
|
captures.Add((
|
|
Path.GetFullPath(Path.Combine(
|
|
captureDirectory,
|
|
string.Format(CultureInfo.InvariantCulture, options.OutputPattern, captureFrame))),
|
|
captureFrame));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
captures.Add((options.OutputPath, options.Frame));
|
|
}
|
|
|
|
long totalBytes = 0;
|
|
foreach (var capture in captures)
|
|
{
|
|
var outputDirectory = Path.GetDirectoryName(capture.OutputPath);
|
|
if (!string.IsNullOrWhiteSpace(outputDirectory))
|
|
{
|
|
Directory.CreateDirectory(outputDirectory);
|
|
}
|
|
|
|
if (File.Exists(capture.OutputPath))
|
|
{
|
|
File.Delete(capture.OutputPath);
|
|
}
|
|
|
|
Console.WriteLine($"[SAVE-IMAGE] Calling SaveSceneImage() frame={capture.Frame} output={capture.OutputPath}...");
|
|
handler.ResetSaveSceneImageTask();
|
|
scene.SaveSceneImage(capture.OutputPath, options.Width, options.Height, capture.Frame);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.SaveSceneImageTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new SaveSceneImageProbeResult(true, "SUCCESS", "TIMEOUT", capture.OutputPath, "OnSaveSceneImage timed out."));
|
|
return;
|
|
}
|
|
|
|
var saveResult = handler.SaveSceneImageTask.Result;
|
|
if (saveResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SaveSceneImageProbeResult(true, "SUCCESS", saveResult.ToString(), capture.OutputPath, $"OnSaveSceneImage result={saveResult}"));
|
|
return;
|
|
}
|
|
|
|
var savedThisFrame = false;
|
|
var fileWaitDeadline = DateTime.UtcNow + options.Connection.Timeout;
|
|
while (DateTime.UtcNow < fileWaitDeadline)
|
|
{
|
|
if (File.Exists(capture.OutputPath))
|
|
{
|
|
var info = new FileInfo(capture.OutputPath);
|
|
if (info.Length > 0)
|
|
{
|
|
totalBytes += info.Length;
|
|
savedThisFrame = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Thread.Sleep(50);
|
|
}
|
|
|
|
if (!savedThisFrame)
|
|
{
|
|
completion.TrySetResult(new SaveSceneImageProbeResult(true, "SUCCESS", "FAILED", capture.OutputPath, "Image file was not created."));
|
|
return;
|
|
}
|
|
}
|
|
|
|
var resultOutput = options.Frames.Count > 0
|
|
? options.OutputDirectory ?? options.OutputPath
|
|
: options.OutputPath;
|
|
var detail = captures.Count == 1
|
|
? $"Saved {totalBytes} bytes."
|
|
: $"Saved {captures.Count} frames ({totalBytes} bytes).";
|
|
completion.TrySetResult(new SaveSceneImageProbeResult(true, "SUCCESS", "SUCCESS", resultOutput, detail));
|
|
}
|
|
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);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
var entries = new List<SceneCatalogEntry>();
|
|
var failures = new List<SceneCatalogFailure>();
|
|
|
|
try
|
|
{
|
|
var handler = new ProbeEventHandler();
|
|
var engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[CATALOG] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[CATALOG] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new SceneCatalogProbeResult(false, 0, 0, options.OutputPath, failures));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
failures.Add(new SceneCatalogFailure("(connect)", "OnConnect timed out."));
|
|
completion.TrySetResult(new SceneCatalogProbeResult(true, 0, 0, options.OutputPath, failures));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
failures.Add(new SceneCatalogFailure("(connect)", $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
completion.TrySetResult(new SceneCatalogProbeResult(true, 0, 0, options.OutputPath, failures));
|
|
return;
|
|
}
|
|
|
|
var scenePaths = Directory
|
|
.EnumerateFiles(options.RootPath, "*.tscn", SearchOption.AllDirectories)
|
|
.Where(path => string.IsNullOrWhiteSpace(options.SceneFilter) ||
|
|
path.Contains(options.SceneFilter, StringComparison.OrdinalIgnoreCase))
|
|
.Select(path => new
|
|
{
|
|
Path = path,
|
|
RelativePath = Path.GetRelativePath(options.RootPath, path)
|
|
})
|
|
.OrderBy(item => item.RelativePath.Count(character =>
|
|
character == Path.DirectorySeparatorChar ||
|
|
character == Path.AltDirectorySeparatorChar))
|
|
.ThenBy(item => item.RelativePath, StringComparer.OrdinalIgnoreCase)
|
|
.Select(item => item.Path)
|
|
.Take(options.MaxScenes ?? int.MaxValue)
|
|
.ToArray();
|
|
|
|
for (var index = 0; index < scenePaths.Length; index++)
|
|
{
|
|
var scenePath = scenePaths[index];
|
|
var sceneAlias = $"catalog_{index:D4}";
|
|
Console.WriteLine($"[CATALOG] ({index + 1}/{scenePaths.Length}) {scenePath}");
|
|
|
|
try
|
|
{
|
|
handler.ResetLoadSceneTask();
|
|
handler.ResetObjectInfosTask();
|
|
var scene = engine.LoadScene(scenePath, sceneAlias);
|
|
if (scene is null)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, "LoadScene returned null."));
|
|
continue;
|
|
}
|
|
|
|
handler.ConfigureQueryObjectInfosOnLoad(scene);
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, "OnLoadScene timed out."));
|
|
continue;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
continue;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectInfosTask, options.Connection.Timeout))
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, "OnQueryObjectInfos timed out."));
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
continue;
|
|
}
|
|
|
|
var objectInfosResult = handler.ObjectInfosTask.Result;
|
|
if (objectInfosResult.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
var reason = string.IsNullOrWhiteSpace(objectInfosResult.Detail)
|
|
? $"OnQueryObjectInfos result={objectInfosResult.Result}"
|
|
: $"OnQueryObjectInfos result={objectInfosResult.Result} detail={objectInfosResult.Detail}";
|
|
failures.Add(new SceneCatalogFailure(scenePath, reason));
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
continue;
|
|
}
|
|
|
|
entries.Add(new SceneCatalogEntry(
|
|
scenePath,
|
|
Path.GetRelativePath(options.RootPath, scenePath),
|
|
objectInfosResult.Objects));
|
|
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, ex.Message));
|
|
}
|
|
}
|
|
|
|
WriteCatalogMarkdown(options, entries, failures);
|
|
completion.TrySetResult(new SceneCatalogProbeResult(true, scenePaths.Length, entries.Count, options.OutputPath, failures));
|
|
|
|
try
|
|
{
|
|
engine.Disconnect();
|
|
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
failures.Add(new SceneCatalogFailure("(exception)", ex.ToString()));
|
|
completion.TrySetResult(new SceneCatalogProbeResult(false, entries.Count + failures.Count, entries.Count, options.OutputPath, failures));
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "KarismaSceneCatalog"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<SceneObjectInspectionProbeResult> InspectSceneObjectsAsync(SceneObjectInspectionOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<SceneObjectInspectionProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
IKAScene? scene = null;
|
|
ProbeEventHandler? handler = null;
|
|
IKAEngine? engine = null;
|
|
|
|
try
|
|
{
|
|
handler = new ProbeEventHandler();
|
|
engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[INSPECT-OBJECTS] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[INSPECT-OBJECTS] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(false, "NOT_RUN", "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, "NOT_RUN", "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, "NOT_RUN", "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[INSPECT-OBJECTS] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, "FAILED", "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, "TIMEOUT", "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, handler.LoadSceneTask.Result.ToString(), "NOT_RUN", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[INSPECT-OBJECTS] Querying object infos...");
|
|
handler.ResetObjectInfosTask();
|
|
scene.QueryObjectInfos();
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectInfosTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(true, "SUCCESS", "TIMEOUT", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), "OnQueryObjectInfos timed out."));
|
|
return;
|
|
}
|
|
|
|
var objectInfosResult = handler.ObjectInfosTask.Result;
|
|
var objects = objectInfosResult.Objects
|
|
.Where(item => string.IsNullOrWhiteSpace(options.NameFilter) ||
|
|
item.Name.Contains(options.NameFilter, StringComparison.OrdinalIgnoreCase))
|
|
.OrderBy(item => item.Name, StringComparer.OrdinalIgnoreCase)
|
|
.ToArray();
|
|
WriteSceneObjectInspectionReport(options, objectInfosResult, objects);
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
objectInfosResult.Result.ToString(),
|
|
options.OutputPath,
|
|
objects,
|
|
objectInfosResult.Detail));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneObjectInspectionProbeResult(false, "EXCEPTION", "EXCEPTION", options.OutputPath, Array.Empty<SceneObjectCatalogItem>(), 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 = "KarismaSceneObjectInspection"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<ObjectTypeQueryProbeResult> QueryObjectTypesAsync(ObjectTypeQueryOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<ObjectTypeQueryProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
IKAScene? scene = null;
|
|
ProbeEventHandler? handler = null;
|
|
IKAEngine? engine = null;
|
|
|
|
try
|
|
{
|
|
handler = new ProbeEventHandler();
|
|
engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[QUERY-OBJECT-TYPES] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[QUERY-OBJECT-TYPES] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(false, "NOT_RUN", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[QUERY-OBJECT-TYPES] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(true, "FAILED", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(true, "TIMEOUT", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectTypeQueryProbeResult(true, handler.LoadSceneTask.Result.ToString(), options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
var items = new List<ObjectTypeQueryItem>(options.ObjectNames.Count);
|
|
foreach (var objectName in options.ObjectNames)
|
|
{
|
|
Console.WriteLine($"[QUERY-OBJECT-TYPES] Querying object={objectName}...");
|
|
var sceneObject = scene.GetObject(objectName);
|
|
if (sceneObject is null)
|
|
{
|
|
items.Add(new ObjectTypeQueryItem(objectName, "OBJECT_NOT_FOUND", eKObjectType.OBJECT_TYPE_UNKNOWN, "GetObject returned null."));
|
|
continue;
|
|
}
|
|
|
|
handler.ResetObjectTypeTask();
|
|
sceneObject.QueryObjectType();
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectTypeTask, options.Connection.Timeout))
|
|
{
|
|
items.Add(new ObjectTypeQueryItem(objectName, "TIMEOUT", eKObjectType.OBJECT_TYPE_UNKNOWN, "OnQueryObjectType timed out."));
|
|
continue;
|
|
}
|
|
|
|
var objectTypeResult = handler.ObjectTypeTask.Result;
|
|
items.Add(new ObjectTypeQueryItem(
|
|
objectName,
|
|
objectTypeResult.Result.ToString(),
|
|
objectTypeResult.ObjectType,
|
|
objectTypeResult.Detail));
|
|
}
|
|
|
|
WriteObjectTypeQueryReport(options, items);
|
|
completion.TrySetResult(new ObjectTypeQueryProbeResult(true, "SUCCESS", options.OutputPath, items, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new ObjectTypeQueryProbeResult(false, "EXCEPTION", options.OutputPath, Array.Empty<ObjectTypeQueryItem>(), 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 = "KarismaObjectTypeQuery"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<ObjectRuntimeInspectionProbeResult> InspectObjectRuntimeAsync(ObjectTypeQueryOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<ObjectRuntimeInspectionProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
IKAScene? scene = null;
|
|
ProbeEventHandler? handler = null;
|
|
IKAEngine? engine = null;
|
|
|
|
try
|
|
{
|
|
handler = new ProbeEventHandler();
|
|
engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[INSPECT-OBJECT-RUNTIME] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[INSPECT-OBJECT-RUNTIME] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(false, "NOT_RUN", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[INSPECT-OBJECT-RUNTIME] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(true, "FAILED", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(true, "TIMEOUT", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new ObjectRuntimeInspectionProbeResult(true, handler.LoadSceneTask.Result.ToString(), options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
var items = new List<ObjectRuntimeInspectionItem>(options.ObjectNames.Count);
|
|
foreach (var objectName in options.ObjectNames)
|
|
{
|
|
Console.WriteLine($"[INSPECT-OBJECT-RUNTIME] Inspecting object={objectName}...");
|
|
var sceneObject = scene.GetObject(objectName);
|
|
if (sceneObject is null)
|
|
{
|
|
items.Add(new ObjectRuntimeInspectionItem(
|
|
objectName,
|
|
"OBJECT_NOT_FOUND",
|
|
eKObjectType.OBJECT_TYPE_UNKNOWN,
|
|
string.Empty,
|
|
"OBJECT_NOT_FOUND",
|
|
null,
|
|
null,
|
|
null,
|
|
"GetObject returned null."));
|
|
continue;
|
|
}
|
|
|
|
var detailParts = new List<string>();
|
|
string animationName;
|
|
try
|
|
{
|
|
animationName = sceneObject.GetAnimationName() ?? string.Empty;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
animationName = string.Empty;
|
|
detailParts.Add($"GetAnimationName: {ex.Message}");
|
|
}
|
|
|
|
handler.ResetObjectTypeTask();
|
|
sceneObject.QueryObjectType();
|
|
string typeResultText;
|
|
var objectType = eKObjectType.OBJECT_TYPE_UNKNOWN;
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectTypeTask, options.Connection.Timeout))
|
|
{
|
|
typeResultText = "TIMEOUT";
|
|
detailParts.Add("OnQueryObjectType timed out.");
|
|
}
|
|
else
|
|
{
|
|
var objectTypeResult = handler.ObjectTypeTask.Result;
|
|
typeResultText = objectTypeResult.Result.ToString();
|
|
objectType = objectTypeResult.ObjectType;
|
|
if (!string.IsNullOrWhiteSpace(objectTypeResult.Detail))
|
|
{
|
|
detailParts.Add($"QueryObjectType: {objectTypeResult.Detail}");
|
|
}
|
|
}
|
|
|
|
handler.ResetQueryPositionTask();
|
|
sceneObject.QueryPosition();
|
|
string positionResultText;
|
|
float? x = null;
|
|
float? y = null;
|
|
float? z = null;
|
|
if (!WaitForTaskWithMessagePump(handler.QueryPositionTask, options.Connection.Timeout))
|
|
{
|
|
positionResultText = "TIMEOUT";
|
|
detailParts.Add("OnQueryPosition timed out.");
|
|
}
|
|
else
|
|
{
|
|
var positionResult = handler.QueryPositionTask.Result;
|
|
positionResultText = positionResult.Result.ToString();
|
|
if (positionResult.Result == eKResult.RESULT_SUCCESS)
|
|
{
|
|
x = positionResult.X;
|
|
y = positionResult.Y;
|
|
z = positionResult.Z;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(positionResult.Detail))
|
|
{
|
|
detailParts.Add($"QueryPosition: {positionResult.Detail}");
|
|
}
|
|
}
|
|
|
|
items.Add(new ObjectRuntimeInspectionItem(
|
|
objectName,
|
|
typeResultText,
|
|
objectType,
|
|
animationName,
|
|
positionResultText,
|
|
x,
|
|
y,
|
|
z,
|
|
string.Join("; ", detailParts.Where(part => !string.IsNullOrWhiteSpace(part)))));
|
|
}
|
|
|
|
WriteObjectRuntimeInspectionReport(options, items);
|
|
completion.TrySetResult(new ObjectRuntimeInspectionProbeResult(true, "SUCCESS", options.OutputPath, items, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new ObjectRuntimeInspectionProbeResult(false, "EXCEPTION", options.OutputPath, Array.Empty<ObjectRuntimeInspectionItem>(), 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 = "KarismaObjectRuntimeInspection"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<ScreenPointInspectionProbeResult> InspectScreenPointsAsync(ScreenPointInspectionOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<ScreenPointInspectionProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
IKAScene? scene = null;
|
|
ProbeEventHandler? handler = null;
|
|
IKAEngine? engine = null;
|
|
|
|
try
|
|
{
|
|
handler = new ProbeEventHandler();
|
|
engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[QUERY-SCREEN-POINT] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[QUERY-SCREEN-POINT] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(false, "NOT_RUN", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[QUERY-SCREEN-POINT] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(true, "FAILED", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(true, "TIMEOUT", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new ScreenPointInspectionProbeResult(true, handler.LoadSceneTask.Result.ToString(), options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
var items = new List<ScreenPointInspectionItem>(options.Points.Count);
|
|
foreach (var point in options.Points)
|
|
{
|
|
Console.WriteLine($"[QUERY-SCREEN-POINT] Querying point=({point.X},{point.Y})...");
|
|
handler.ResetObjectInfosTask();
|
|
scene.QueryObjectInfosByScreenPoint(point.X, point.Y);
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectInfosTask, options.Connection.Timeout))
|
|
{
|
|
items.Add(new ScreenPointInspectionItem(point.X, point.Y, "TIMEOUT", Array.Empty<SceneObjectCatalogItem>(), "OnQueryObjectInfosByScreenPoint timed out."));
|
|
continue;
|
|
}
|
|
|
|
var objectInfosResult = handler.ObjectInfosTask.Result;
|
|
items.Add(new ScreenPointInspectionItem(
|
|
point.X,
|
|
point.Y,
|
|
objectInfosResult.Result.ToString(),
|
|
objectInfosResult.Objects,
|
|
objectInfosResult.Detail));
|
|
}
|
|
|
|
WriteScreenPointInspectionReport(options, items);
|
|
completion.TrySetResult(new ScreenPointInspectionProbeResult(true, "SUCCESS", options.OutputPath, items, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new ScreenPointInspectionProbeResult(false, "EXCEPTION", options.OutputPath, Array.Empty<ScreenPointInspectionItem>(), 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 = "KarismaScreenPointInspection"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<SceneCapabilityInspectionProbeResult> InspectSceneCapabilitiesAsync(SceneCapabilityInspectionOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<SceneCapabilityInspectionProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
IKAScene? scene = null;
|
|
ProbeEventHandler? handler = null;
|
|
IKAEngine? engine = null;
|
|
|
|
try
|
|
{
|
|
handler = new ProbeEventHandler();
|
|
engine = (IKAEngine)new KAEngineClass();
|
|
|
|
var samplePngPath = FindFirstFile(Environment.CurrentDirectory, "*.png");
|
|
Console.WriteLine($"[INSPECT-CAPABILITIES] Sample PNG={(samplePngPath ?? "(none)")}");
|
|
|
|
Console.WriteLine("[INSPECT-CAPABILITIES] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[INSPECT-CAPABILITIES] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(false, "NOT_RUN", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(true, "NOT_RUN", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("[INSPECT-CAPABILITIES] Loading scene...");
|
|
handler.ResetLoadSceneTask();
|
|
scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(true, "FAILED", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(true, "TIMEOUT", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneCapabilityInspectionProbeResult(true, handler.LoadSceneTask.Result.ToString(), options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
var candidates = ExtractCandidateNames(options.ScenePath)
|
|
.Where(candidate => options.Keywords.Count == 0 ||
|
|
options.Keywords.Any(keyword => candidate.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
|
|
.OrderBy(candidate => candidate, StringComparer.OrdinalIgnoreCase)
|
|
.Take(options.MaxCandidates ?? int.MaxValue)
|
|
.ToArray();
|
|
|
|
var items = new List<SceneCapabilityInspectionItem>(candidates.Length);
|
|
foreach (var candidate in candidates)
|
|
{
|
|
Console.WriteLine($"[INSPECT-CAPABILITIES] Inspecting candidate={candidate}...");
|
|
KAObject? sceneObject;
|
|
try
|
|
{
|
|
sceneObject = scene.GetObject(candidate);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
items.Add(new SceneCapabilityInspectionItem(
|
|
candidate,
|
|
false,
|
|
string.Empty,
|
|
false,
|
|
false,
|
|
false,
|
|
"GET_OBJECT_EXCEPTION",
|
|
eKObjectType.OBJECT_TYPE_UNKNOWN,
|
|
string.Empty,
|
|
null,
|
|
null,
|
|
null,
|
|
string.Empty,
|
|
string.Empty,
|
|
string.Empty,
|
|
string.Empty,
|
|
ex.Message));
|
|
continue;
|
|
}
|
|
|
|
if (sceneObject is null)
|
|
{
|
|
items.Add(new SceneCapabilityInspectionItem(
|
|
candidate,
|
|
false,
|
|
string.Empty,
|
|
false,
|
|
false,
|
|
false,
|
|
"OBJECT_NOT_FOUND",
|
|
eKObjectType.OBJECT_TYPE_UNKNOWN,
|
|
string.Empty,
|
|
null,
|
|
null,
|
|
null,
|
|
string.Empty,
|
|
string.Empty,
|
|
string.Empty,
|
|
string.Empty,
|
|
"GetObject returned null."));
|
|
continue;
|
|
}
|
|
|
|
var detailParts = new List<string>();
|
|
string animationName;
|
|
try
|
|
{
|
|
animationName = sceneObject.GetAnimationName() ?? string.Empty;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
animationName = string.Empty;
|
|
detailParts.Add($"GetAnimationName: {ex.Message}");
|
|
}
|
|
|
|
handler.ResetObjectTypeTask();
|
|
sceneObject.QueryObjectType();
|
|
string queryTypeResult;
|
|
var objectType = eKObjectType.OBJECT_TYPE_UNKNOWN;
|
|
if (!WaitForTaskWithMessagePump(handler.ObjectTypeTask, options.Connection.Timeout))
|
|
{
|
|
queryTypeResult = "TIMEOUT";
|
|
detailParts.Add("OnQueryObjectType timed out.");
|
|
}
|
|
else
|
|
{
|
|
var callbackResult = handler.ObjectTypeTask.Result;
|
|
queryTypeResult = callbackResult.Result.ToString();
|
|
objectType = callbackResult.ObjectType;
|
|
}
|
|
|
|
var isChart = objectType == eKObjectType.OBJECT_TYPE_CHART;
|
|
var isCounter = objectType == eKObjectType.OBJECT_TYPE_COUNTER;
|
|
var isPath = objectType is eKObjectType.OBJECT_TYPE_PATH or eKObjectType.OBJECT_TYPE_PATHSHAPE;
|
|
|
|
handler.ResetQueryPositionTask();
|
|
sceneObject.QueryPosition();
|
|
string queryPositionResult;
|
|
float? x = null;
|
|
float? y = null;
|
|
float? z = null;
|
|
if (!WaitForTaskWithMessagePump(handler.QueryPositionTask, options.Connection.Timeout))
|
|
{
|
|
queryPositionResult = "TIMEOUT";
|
|
detailParts.Add("OnQueryPosition timed out.");
|
|
}
|
|
else
|
|
{
|
|
var callbackResult = handler.QueryPositionTask.Result;
|
|
queryPositionResult = callbackResult.Result.ToString();
|
|
if (callbackResult.Result == eKResult.RESULT_SUCCESS)
|
|
{
|
|
x = callbackResult.X;
|
|
y = callbackResult.Y;
|
|
z = callbackResult.Z;
|
|
}
|
|
}
|
|
|
|
var setPositionResult = string.Empty;
|
|
if (x.HasValue && y.HasValue && z.HasValue)
|
|
{
|
|
handler.ResetPositionTask();
|
|
sceneObject.SetPosition(x.Value, y.Value, z.Value, eKVectorType.VECTOR_TYPE_XYZ);
|
|
if (!WaitForTaskWithMessagePump(handler.PositionTask, options.Connection.Timeout))
|
|
{
|
|
setPositionResult = "TIMEOUT";
|
|
detailParts.Add("OnSetPosition timed out.");
|
|
}
|
|
else
|
|
{
|
|
setPositionResult = handler.PositionTask.Result.ToString();
|
|
}
|
|
}
|
|
|
|
var setValueTextResult = TrySetValueOnObject(handler, sceneObject, "__TCP_VALIDATE__", options.Connection.Timeout).ToString();
|
|
var setValueImageResult = string.Empty;
|
|
if (!string.IsNullOrWhiteSpace(samplePngPath))
|
|
{
|
|
setValueImageResult = TrySetValueOnObject(handler, sceneObject, samplePngPath, options.Connection.Timeout).ToString();
|
|
}
|
|
|
|
var counterKeyResult = string.Empty;
|
|
if (isCounter && sceneObject is IKACounter counter)
|
|
{
|
|
handler.ResetCounterNumberKeyTask();
|
|
counter.SetCounterNumberKey(1, 1d);
|
|
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, options.Connection.Timeout))
|
|
{
|
|
counterKeyResult = "TIMEOUT";
|
|
detailParts.Add("OnSetCounterNumberKey timed out.");
|
|
}
|
|
else
|
|
{
|
|
counterKeyResult = handler.CounterNumberKeyTask.Result.ToString();
|
|
}
|
|
}
|
|
|
|
items.Add(new SceneCapabilityInspectionItem(
|
|
candidate,
|
|
true,
|
|
animationName,
|
|
isChart,
|
|
isCounter,
|
|
isPath,
|
|
queryTypeResult,
|
|
objectType,
|
|
queryPositionResult,
|
|
x,
|
|
y,
|
|
z,
|
|
setPositionResult,
|
|
setValueTextResult,
|
|
setValueImageResult,
|
|
counterKeyResult,
|
|
string.Join("; ", detailParts.Where(part => !string.IsNullOrWhiteSpace(part)))));
|
|
}
|
|
|
|
WriteSceneCapabilityInspectionReport(options, items);
|
|
completion.TrySetResult(new SceneCapabilityInspectionProbeResult(true, "SUCCESS", options.OutputPath, items, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new SceneCapabilityInspectionProbeResult(false, "EXCEPTION", options.OutputPath, Array.Empty<SceneCapabilityInspectionItem>(), 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 = "KarismaSceneCapabilityInspection"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<SceneValidationProbeResult> ValidateSceneOperationsAsync(SceneValidationOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<SceneValidationProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
var operations = LoadValidationOperations(options);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
try
|
|
{
|
|
var handler = new ProbeEventHandler();
|
|
var engine = (IKAEngine)new KAEngineClass();
|
|
var results = new List<SceneOperationValidationResult>();
|
|
|
|
Console.WriteLine("[VALIDATE] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[VALIDATE] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(false, "NOT_RUN", 0, operations.Count, options.OutputPath, "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(true, "NOT_RUN", 0, operations.Count, options.OutputPath, "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(true, "NOT_RUN", 0, operations.Count, options.OutputPath, $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
handler.ResetLoadSceneTask();
|
|
var scene = engine.LoadScene(options.ScenePath, options.SceneAlias);
|
|
if (scene is null)
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(true, "FAILED", 0, operations.Count, options.OutputPath, "LoadScene returned null."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(true, "TIMEOUT", 0, operations.Count, options.OutputPath, "OnLoadScene timed out."));
|
|
return;
|
|
}
|
|
|
|
var loadSceneResult = handler.LoadSceneTask.Result;
|
|
if (loadSceneResult != eKResult.RESULT_SUCCESS)
|
|
{
|
|
completion.TrySetResult(
|
|
new SceneValidationProbeResult(true, loadSceneResult.ToString(), 0, operations.Count, options.OutputPath, $"OnLoadScene result={loadSceneResult}"));
|
|
return;
|
|
}
|
|
|
|
foreach (var operation in operations)
|
|
{
|
|
results.Add(ApplySceneOperation(handler, scene, operation, options.Connection.Timeout));
|
|
}
|
|
|
|
WriteSceneValidationMarkdown(options, results);
|
|
|
|
try
|
|
{
|
|
scene.UnloadScene();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
try
|
|
{
|
|
engine.Disconnect();
|
|
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
completion.TrySetResult(new SceneValidationProbeResult(
|
|
true,
|
|
"SUCCESS",
|
|
results.Count(result => string.Equals(result.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal)),
|
|
results.Count(result => !string.Equals(result.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal)),
|
|
options.OutputPath,
|
|
string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new SceneValidationProbeResult(false, "EXCEPTION", 0, operations.Count, options.OutputPath, ex.ToString()));
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "KarismaSceneValidator"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static Task<FolderInspectionProbeResult> InspectTscnFolderAsync(FolderInspectionOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<FolderInspectionProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
try
|
|
{
|
|
var handler = new ProbeEventHandler();
|
|
var engine = (IKAEngine)new KAEngineClass();
|
|
var sceneResults = new List<SceneInspectionResult>();
|
|
var failures = new List<SceneCatalogFailure>();
|
|
|
|
var imagePngPath = FindFirstFile(options.RootPath, "*.png");
|
|
var imageVrvPath = FindFirstFile(options.RootPath, "*.vrv");
|
|
Console.WriteLine($"[INSPECT] Sample PNG={(imagePngPath ?? "(none)")}");
|
|
Console.WriteLine($"[INSPECT] Sample VRV={(imageVrvPath ?? "(none)")}");
|
|
|
|
Console.WriteLine("[INSPECT] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Connection.Host, options.Connection.Port, handler);
|
|
Console.WriteLine($"[INSPECT] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new FolderInspectionProbeResult(false, 0, 0, 0, 1, options.OutputPath, "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Connection.Timeout))
|
|
{
|
|
completion.TrySetResult(new FolderInspectionProbeResult(true, 0, 0, 0, 1, options.OutputPath, "OnConnect timed out."));
|
|
return;
|
|
}
|
|
|
|
if (handler.ConnectTask.Result != 0)
|
|
{
|
|
completion.TrySetResult(new FolderInspectionProbeResult(true, 0, 0, 0, 1, options.OutputPath, $"OnConnect errorCode={handler.ConnectTask.Result}"));
|
|
return;
|
|
}
|
|
|
|
var scenePaths = Directory
|
|
.EnumerateFiles(options.RootPath, "*.tscn", SearchOption.AllDirectories)
|
|
.Where(path => string.IsNullOrWhiteSpace(options.SceneFilter) ||
|
|
path.Contains(options.SceneFilter, StringComparison.OrdinalIgnoreCase))
|
|
.Select(path => new
|
|
{
|
|
Path = path,
|
|
RelativePath = Path.GetRelativePath(options.RootPath, path)
|
|
})
|
|
.OrderBy(item => item.RelativePath.Count(character =>
|
|
character == Path.DirectorySeparatorChar ||
|
|
character == Path.AltDirectorySeparatorChar))
|
|
.ThenBy(item => item.RelativePath, StringComparer.OrdinalIgnoreCase)
|
|
.Select(item => item.Path)
|
|
.Take(options.MaxScenes ?? int.MaxValue)
|
|
.ToArray();
|
|
|
|
for (var sceneIndex = 0; sceneIndex < scenePaths.Length; sceneIndex++)
|
|
{
|
|
var scenePath = scenePaths[sceneIndex];
|
|
var sceneAlias = $"inspect_{sceneIndex:D4}";
|
|
Console.WriteLine($"[INSPECT] ({sceneIndex + 1}/{scenePaths.Length}) {scenePath}");
|
|
|
|
try
|
|
{
|
|
handler.ResetLoadSceneTask();
|
|
var scene = engine.LoadScene(scenePath, sceneAlias);
|
|
if (scene is null)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, "LoadScene returned null."));
|
|
continue;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.LoadSceneTask, options.Connection.Timeout))
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, "OnLoadScene timed out."));
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
continue;
|
|
}
|
|
|
|
if (handler.LoadSceneTask.Result != eKResult.RESULT_SUCCESS)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, $"OnLoadScene result={handler.LoadSceneTask.Result}"));
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
continue;
|
|
}
|
|
|
|
var candidates = ExtractCandidateNames(scenePath);
|
|
var discoveries = new List<SceneVariableDiscovery>();
|
|
|
|
foreach (var candidate in candidates)
|
|
{
|
|
KAObject? sceneObject;
|
|
try
|
|
{
|
|
sceneObject = scene.GetObject(candidate);
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (sceneObject is null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var textAttempt = TrySetValueOnObject(handler, sceneObject, "__TCP_VALIDATE__", options.Connection.Timeout);
|
|
if (textAttempt == eKResult.RESULT_SUCCESS)
|
|
{
|
|
discoveries.Add(new SceneVariableDiscovery(candidate, "SetValue", "__TCP_VALIDATE__", textAttempt.ToString()));
|
|
continue;
|
|
}
|
|
|
|
if (textAttempt == eKResult.RESULT_ERROR_NO_VARIABLE_OBJECT)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(imagePngPath))
|
|
{
|
|
var pngAttempt = TrySetValueOnObject(handler, sceneObject, imagePngPath, options.Connection.Timeout);
|
|
if (pngAttempt == eKResult.RESULT_SUCCESS)
|
|
{
|
|
discoveries.Add(new SceneVariableDiscovery(candidate, "SetValue", imagePngPath, pngAttempt.ToString()));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(imageVrvPath))
|
|
{
|
|
var vrvAttempt = TrySetValueOnObject(handler, sceneObject, imageVrvPath, options.Connection.Timeout);
|
|
if (vrvAttempt == eKResult.RESULT_SUCCESS)
|
|
{
|
|
discoveries.Add(new SceneVariableDiscovery(candidate, "SetValue", imageVrvPath, vrvAttempt.ToString()));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (sceneObject is IKACounter counter)
|
|
{
|
|
handler.ResetCounterNumberKeyTask();
|
|
counter.SetCounterNumberKey(1, 1d);
|
|
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, options.Connection.Timeout))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var counterResult = handler.CounterNumberKeyTask.Result;
|
|
if (counterResult == eKResult.RESULT_SUCCESS)
|
|
{
|
|
discoveries.Add(new SceneVariableDiscovery(
|
|
candidate,
|
|
"SetCounterNumberKey",
|
|
"keyIndex=1, number=1",
|
|
counterResult.ToString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
sceneResults.Add(new SceneInspectionResult(
|
|
scenePath,
|
|
Path.GetRelativePath(options.RootPath, scenePath),
|
|
candidates.Count,
|
|
discoveries.OrderBy(discovery => discovery.VariableName, StringComparer.Ordinal).ToArray()));
|
|
|
|
TryUnloadScene(handler, scene, options.Connection.Timeout);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
failures.Add(new SceneCatalogFailure(scenePath, ex.Message));
|
|
}
|
|
}
|
|
|
|
WriteFolderInspectionMarkdown(options, sceneResults, failures);
|
|
|
|
try
|
|
{
|
|
engine.Disconnect();
|
|
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
completion.TrySetResult(new FolderInspectionProbeResult(
|
|
true,
|
|
scenePaths.Length,
|
|
sceneResults.Count,
|
|
sceneResults.Sum(result => result.Discoveries.Count),
|
|
failures.Count,
|
|
options.OutputPath,
|
|
string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new FolderInspectionProbeResult(false, 0, 0, 0, 1, options.OutputPath, ex.ToString()));
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "KarismaTscnInspector"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static eKResult TrySetValueOnObject(ProbeEventHandler handler, KAObject sceneObject, string payload, TimeSpan timeout)
|
|
{
|
|
handler.ResetSetValueTask();
|
|
sceneObject.SetValue(payload);
|
|
return WaitForTaskWithMessagePump(handler.SetValueTask, timeout)
|
|
? handler.SetValueTask.Result
|
|
: eKResult.RESULT_FAILURE;
|
|
}
|
|
|
|
static string? FindFirstFile(string rootPath, string pattern)
|
|
{
|
|
try
|
|
{
|
|
return Directory.EnumerateFiles(rootPath, pattern, SearchOption.AllDirectories)
|
|
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
|
|
.FirstOrDefault();
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static IReadOnlyList<string> ExtractCandidateNames(string scenePath)
|
|
{
|
|
var data = File.ReadAllBytes(scenePath);
|
|
var candidates = new HashSet<string>(StringComparer.Ordinal);
|
|
for (var index = 0; index + 8 <= data.Length; index++)
|
|
{
|
|
var length = BitConverter.ToInt32(data, index);
|
|
if (length < 2 || length > 48)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var byteLength = length * 2;
|
|
var start = index + 4;
|
|
var end = start + byteLength;
|
|
if (end > data.Length)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string value;
|
|
try
|
|
{
|
|
value = System.Text.Encoding.Unicode.GetString(data, start, byteLength);
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (IsCandidateName(value))
|
|
{
|
|
candidates.Add(value);
|
|
}
|
|
}
|
|
|
|
return candidates.OrderBy(value => value, StringComparer.Ordinal).ToArray();
|
|
}
|
|
|
|
static bool IsCandidateName(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var trimmed = value.Trim();
|
|
if (trimmed.Length < 2 || trimmed.Length > 48)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (trimmed.Contains('\\') ||
|
|
trimmed.Contains('/') ||
|
|
trimmed.Contains(':') ||
|
|
trimmed.Contains('.') ||
|
|
trimmed.Contains(' '))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (trimmed.All(char.IsDigit))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (trimmed.StartsWith("OBJECT_TYPE_", StringComparison.Ordinal) ||
|
|
trimmed.StartsWith("RESULT_", StringComparison.Ordinal) ||
|
|
trimmed.StartsWith("EFFECT_", StringComparison.Ordinal))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (trimmed is "Tornado3" or "Out" or "Default" or "Image" or "Text" or "Counter" or
|
|
"Rect" or "Paragraph" or "Char" or "Arial" or "Path" or "Group" or "Change")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return trimmed.All(ch =>
|
|
ch is >= '0' and <= '9' ||
|
|
ch is >= 'A' and <= 'Z' ||
|
|
ch is >= 'a' and <= 'z' ||
|
|
ch is >= '\uAC00' and <= '\uD7A3' ||
|
|
ch is '_' or '-');
|
|
}
|
|
|
|
static void WriteFolderInspectionMarkdown(
|
|
FolderInspectionOptions options,
|
|
IReadOnlyList<SceneInspectionResult> sceneResults,
|
|
IReadOnlyList<SceneCatalogFailure> failures)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# TSCN Variable Discovery");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Root: `{options.RootPath}`");
|
|
writer.WriteLine($"- Scene Count: {sceneResults.Count}");
|
|
writer.WriteLine($"- Discovered Variable Count: {sceneResults.Sum(result => result.Discoveries.Count)}");
|
|
writer.WriteLine($"- Failure Count: {failures.Count}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("## Method");
|
|
writer.WriteLine();
|
|
writer.WriteLine("- Candidate names are extracted from each `.tscn` as UTF-16LE strings.");
|
|
writer.WriteLine("- Each candidate is verified through Karisma TCP callbacks.");
|
|
writer.WriteLine("- `SetValue(__TCP_VALIDATE__)`, valid `.png`, valid `.vrv`, and `SetCounterNumberKey(1, 1)` are tried as applicable.");
|
|
writer.WriteLine("- Only callbacks that returned `RESULT_SUCCESS` are listed as discovered variables.");
|
|
writer.WriteLine();
|
|
|
|
if (failures.Count > 0)
|
|
{
|
|
writer.WriteLine("## Failures");
|
|
writer.WriteLine();
|
|
foreach (var failure in failures)
|
|
{
|
|
writer.WriteLine($"- `{failure.ScenePath}`: {EscapeInline(failure.Reason)}");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
}
|
|
|
|
writer.WriteLine("## Scenes");
|
|
writer.WriteLine();
|
|
foreach (var sceneResult in sceneResults)
|
|
{
|
|
writer.WriteLine($"### `{sceneResult.RelativePath}`");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Candidate Count: {sceneResult.CandidateCount}");
|
|
writer.WriteLine($"- Discovered Variables: {sceneResult.Discoveries.Count}");
|
|
writer.WriteLine();
|
|
|
|
if (sceneResult.Discoveries.Count == 0)
|
|
{
|
|
writer.WriteLine("- No variables discovered with the current TCP validation heuristics.");
|
|
writer.WriteLine();
|
|
continue;
|
|
}
|
|
|
|
writer.WriteLine("| Variable | Method | Payload | Result |");
|
|
writer.WriteLine("| --- | --- | --- | --- |");
|
|
foreach (var discovery in sceneResult.Discoveries)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(discovery.VariableName)} | {EscapeCell(discovery.Method)} | {EscapeCell(discovery.Payload)} | {EscapeCell(discovery.Result)} |");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
}
|
|
}
|
|
|
|
static List<SceneValidationOperation> LoadValidationOperations(SceneValidationOptions options)
|
|
{
|
|
return LoadSceneOperations(options.ScenePath, options.OperationsPath);
|
|
}
|
|
|
|
static List<SceneValidationOperation> LoadSceneOperations(string scenePath, string operationsPath)
|
|
{
|
|
var json = File.ReadAllText(operationsPath);
|
|
var operations = JsonSerializer.Deserialize<List<SceneValidationOperation>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
}) ?? new List<SceneValidationOperation>();
|
|
|
|
foreach (var operation in operations)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(operation.Value))
|
|
{
|
|
operation.Value = operation.Value.Replace("${SCENE_DIR}", Path.GetDirectoryName(scenePath) ?? string.Empty, StringComparison.Ordinal);
|
|
}
|
|
}
|
|
|
|
return operations;
|
|
}
|
|
|
|
static SceneOperationValidationResult ApplySceneOperation(
|
|
ProbeEventHandler handler,
|
|
IKAScene scene,
|
|
SceneValidationOperation operation,
|
|
TimeSpan timeout)
|
|
{
|
|
Console.WriteLine($"[VALIDATE] {operation.Method} object={operation.ObjectName}");
|
|
var sceneObject = scene.GetObject(operation.ObjectName);
|
|
if (sceneObject is null)
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"OBJECT_NOT_FOUND",
|
|
"scene.GetObject returned null.");
|
|
}
|
|
|
|
if (string.Equals(operation.Method, "SetCounterNumberKey", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (sceneObject is not IKACounter counter)
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"NOT_A_COUNTER",
|
|
"Object does not implement IKACounter.");
|
|
}
|
|
|
|
handler.ResetCounterNumberKeyTask();
|
|
counter.SetCounterNumberKey(operation.KeyIndex, operation.Number);
|
|
if (!WaitForTaskWithMessagePump(handler.CounterNumberKeyTask, timeout))
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"TIMEOUT",
|
|
"OnSetCounterNumberKey timed out.");
|
|
}
|
|
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
handler.CounterNumberKeyTask.Result.ToString(),
|
|
string.Empty);
|
|
}
|
|
|
|
if (string.Equals(operation.Method, "SetVisible", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
handler.ResetVisibleTask();
|
|
sceneObject.SetVisible(operation.Visible ? 1 : 0);
|
|
if (!WaitForTaskWithMessagePump(handler.VisibleTask, timeout))
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"TIMEOUT",
|
|
"OnSetVisible timed out.");
|
|
}
|
|
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
handler.VisibleTask.Result.ToString(),
|
|
string.Empty);
|
|
}
|
|
|
|
if (string.Equals(operation.Method, "SetStyleColor", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (sceneObject is not IKAStyle style)
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"NOT_A_STYLE_OBJECT",
|
|
"Object does not implement IKAStyle.");
|
|
}
|
|
|
|
handler.ResetStyleColorTask();
|
|
style.SetStyleColor(
|
|
ParseStyleType(operation.StyleType),
|
|
operation.Order,
|
|
operation.R,
|
|
operation.G,
|
|
operation.B,
|
|
operation.A);
|
|
if (!WaitForTaskWithMessagePump(handler.StyleColorTask, timeout))
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"TIMEOUT",
|
|
"OnSetStyleColor timed out.");
|
|
}
|
|
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
handler.StyleColorTask.Result.ToString(),
|
|
string.Empty);
|
|
}
|
|
|
|
handler.ResetSetValueTask();
|
|
sceneObject.SetValue(operation.Value ?? string.Empty);
|
|
if (!WaitForTaskWithMessagePump(handler.SetValueTask, timeout))
|
|
{
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
"TIMEOUT",
|
|
"OnSetValue timed out.");
|
|
}
|
|
|
|
return new SceneOperationValidationResult(
|
|
operation.ObjectName,
|
|
operation.Method,
|
|
DescribeOperationPayload(operation),
|
|
handler.SetValueTask.Result.ToString(),
|
|
string.Empty);
|
|
}
|
|
|
|
static string DescribeOperationPayload(SceneValidationOperation operation)
|
|
{
|
|
if (string.Equals(operation.Method, "SetVisible", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return $"visible={operation.Visible}";
|
|
}
|
|
|
|
if (string.Equals(operation.Method, "SetStyleColor", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return $"styleType={operation.StyleType}, order={operation.Order}, rgba=({operation.R}, {operation.G}, {operation.B}, {operation.A})";
|
|
}
|
|
|
|
return string.Equals(operation.Method, "SetCounterNumberKey", StringComparison.OrdinalIgnoreCase)
|
|
? $"keyIndex={operation.KeyIndex}, number={operation.Number:0.###}"
|
|
: operation.Value ?? string.Empty;
|
|
}
|
|
|
|
static eKStyleType ParseStyleType(string? value)
|
|
{
|
|
return (value ?? string.Empty).Trim().ToLowerInvariant() switch
|
|
{
|
|
"face" => eKStyleType.STYLE_TYPE_FACE,
|
|
"edge" => eKStyleType.STYLE_TYPE_EDGE,
|
|
"shadow" => eKStyleType.STYLE_TYPE_SHADOW,
|
|
"underline" => eKStyleType.STYLE_TYPE_UNDERLINE,
|
|
"frame" => eKStyleType.STYLE_TYPE_FRAME,
|
|
_ => throw new ArgumentException($"Unsupported style type: {value}")
|
|
};
|
|
}
|
|
|
|
static void WriteSceneValidationMarkdown(SceneValidationOptions options, IReadOnlyList<SceneOperationValidationResult> results)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Scene Variable Validation");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Operations: `{options.OperationsPath}`");
|
|
writer.WriteLine($"- Success Count: {results.Count(result => string.Equals(result.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal))}");
|
|
writer.WriteLine($"- Failure Count: {results.Count(result => !string.Equals(result.Result, eKResult.RESULT_SUCCESS.ToString(), StringComparison.Ordinal))}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Object | Method | Payload | Result | Detail |");
|
|
writer.WriteLine("| --- | --- | --- | --- | --- |");
|
|
foreach (var result in results)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(result.ObjectName)} | {EscapeCell(result.Method)} | {EscapeCell(result.Payload)} | {EscapeCell(result.Result)} | {EscapeCell(result.Detail)} |");
|
|
}
|
|
}
|
|
|
|
static void TryUnloadScene(ProbeEventHandler handler, IKAScene scene, TimeSpan timeout)
|
|
{
|
|
try
|
|
{
|
|
handler.ResetUnloadSceneTask();
|
|
scene.UnloadScene();
|
|
WaitForTaskWithMessagePump(handler.UnloadSceneTask, timeout);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
static void WriteCatalogMarkdown(
|
|
SceneCatalogOptions options,
|
|
IReadOnlyList<SceneCatalogEntry> entries,
|
|
IReadOnlyList<SceneCatalogFailure> failures)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Scene Object Catalog");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Root: `{options.RootPath}`");
|
|
writer.WriteLine($"- Scene Count: {entries.Count}");
|
|
writer.WriteLine($"- Failure Count: {failures.Count}");
|
|
writer.WriteLine();
|
|
|
|
if (failures.Count > 0)
|
|
{
|
|
writer.WriteLine("## Failures");
|
|
writer.WriteLine();
|
|
foreach (var failure in failures)
|
|
{
|
|
writer.WriteLine($"- `{failure.ScenePath}`: {EscapeInline(failure.Reason)}");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
}
|
|
|
|
writer.WriteLine("## Scenes");
|
|
writer.WriteLine();
|
|
foreach (var entry in entries)
|
|
{
|
|
writer.WriteLine($"### `{entry.RelativePath}`");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Object Count: {entry.Objects.Count}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Name | Type | Value | Visible |");
|
|
writer.WriteLine("| --- | --- | --- | --- |");
|
|
foreach (var obj in entry.Objects)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(obj.Name)} | {obj.ObjectType} | {EscapeCell(obj.Value)} | {(obj.Visible ? "true" : "false")} |");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
}
|
|
}
|
|
|
|
static void WriteSceneObjectInspectionReport(
|
|
SceneObjectInspectionOptions options,
|
|
ObjectInfosProbeResult probeResult,
|
|
IReadOnlyList<SceneObjectCatalogItem> objects)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Scene Object Inspection");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Query Result: `{probeResult.Result}`");
|
|
writer.WriteLine($"- Object Count: {objects.Count}");
|
|
if (!string.IsNullOrWhiteSpace(options.NameFilter))
|
|
{
|
|
writer.WriteLine($"- Name Filter: `{options.NameFilter}`");
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(probeResult.Detail))
|
|
{
|
|
writer.WriteLine($"- Detail: {EscapeInline(probeResult.Detail)}");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
writer.WriteLine("## Type Counts");
|
|
writer.WriteLine();
|
|
foreach (var typeGroup in objects.GroupBy(item => item.ObjectType).OrderBy(group => group.Key.ToString(), StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
writer.WriteLine($"- `{typeGroup.Key}`: {typeGroup.Count()}");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
writer.WriteLine("## Objects");
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Name | Type | Visible | Value |");
|
|
writer.WriteLine("| --- | --- | --- | --- |");
|
|
foreach (var item in objects)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(item.Name)} | {EscapeCell(item.ObjectType.ToString())} | {(item.Visible ? "yes" : "no")} | {EscapeCell(item.Value)} |");
|
|
}
|
|
}
|
|
|
|
static void WriteObjectTypeQueryReport(
|
|
ObjectTypeQueryOptions options,
|
|
IReadOnlyList<ObjectTypeQueryItem> items)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Object Type Query");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Objects Queried: {items.Count}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Object | Result | Type | Detail |");
|
|
writer.WriteLine("| --- | --- | --- | --- |");
|
|
foreach (var item in items)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(item.ObjectName)} | {EscapeCell(item.Result)} | {EscapeCell(item.ObjectType.ToString())} | {EscapeCell(item.Detail)} |");
|
|
}
|
|
}
|
|
|
|
static void WriteObjectRuntimeInspectionReport(
|
|
ObjectTypeQueryOptions options,
|
|
IReadOnlyList<ObjectRuntimeInspectionItem> items)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Object Runtime Inspection");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Objects Inspected: {items.Count}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Object | Type Result | Type | Animation | Position Result | X | Y | Z | Detail |");
|
|
writer.WriteLine("| --- | --- | --- | --- | --- | --- | --- | --- | --- |");
|
|
foreach (var item in items)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(item.ObjectName)} | {EscapeCell(item.TypeResult)} | {EscapeCell(item.ObjectType.ToString())} | {EscapeCell(item.AnimationName)} | {EscapeCell(item.PositionResult)} | {EscapeCell(FormatCoordinate(item.X))} | {EscapeCell(FormatCoordinate(item.Y))} | {EscapeCell(FormatCoordinate(item.Z))} | {EscapeCell(item.Detail)} |");
|
|
}
|
|
}
|
|
|
|
static void WriteScreenPointInspectionReport(
|
|
ScreenPointInspectionOptions options,
|
|
IReadOnlyList<ScreenPointInspectionItem> items)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Screen Point Inspection");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Points Inspected: {items.Count}");
|
|
writer.WriteLine();
|
|
|
|
foreach (var item in items)
|
|
{
|
|
writer.WriteLine($"## ({item.X}, {item.Y})");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Result: `{item.Result}`");
|
|
if (!string.IsNullOrWhiteSpace(item.Detail))
|
|
{
|
|
writer.WriteLine($"- Detail: {EscapeInline(item.Detail)}");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Name | Type | Visible | Value |");
|
|
writer.WriteLine("| --- | --- | --- | --- |");
|
|
foreach (var sceneObject in item.Objects)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(sceneObject.Name)} | {EscapeCell(sceneObject.ObjectType.ToString())} | {(sceneObject.Visible ? "yes" : "no")} | {EscapeCell(sceneObject.Value)} |");
|
|
}
|
|
|
|
if (item.Objects.Count == 0)
|
|
{
|
|
writer.WriteLine("_No objects returned._");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
}
|
|
}
|
|
|
|
static void WriteSceneCapabilityInspectionReport(
|
|
SceneCapabilityInspectionOptions options,
|
|
IReadOnlyList<SceneCapabilityInspectionItem> items)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(options.OutputPath)!);
|
|
|
|
using var writer = new StreamWriter(options.OutputPath, false, new System.Text.UTF8Encoding(false));
|
|
writer.WriteLine("# Scene Capability Inspection");
|
|
writer.WriteLine();
|
|
writer.WriteLine($"- Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
writer.WriteLine($"- Scene: `{options.ScenePath}`");
|
|
writer.WriteLine($"- Candidate Count: {items.Count}");
|
|
if (options.Keywords.Count > 0)
|
|
{
|
|
writer.WriteLine($"- Keywords: `{string.Join("; ", options.Keywords)}`");
|
|
}
|
|
|
|
writer.WriteLine();
|
|
writer.WriteLine("| Candidate | Found | Anim | Chart | Counter | Path | QueryType | Type | QueryPos | X | Y | Z | SetPos | SetValueText | SetValueImage | CounterKey | Detail |");
|
|
writer.WriteLine("| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |");
|
|
foreach (var item in items)
|
|
{
|
|
writer.WriteLine(
|
|
$"| {EscapeCell(item.Candidate)} | {(item.ObjectFound ? "yes" : "no")} | {EscapeCell(item.AnimationName)} | {(item.IsChart ? "yes" : "no")} | {(item.IsCounter ? "yes" : "no")} | {(item.IsPath ? "yes" : "no")} | {EscapeCell(item.QueryTypeResult)} | {EscapeCell(item.ObjectType.ToString())} | {EscapeCell(item.QueryPositionResult)} | {EscapeCell(FormatCoordinate(item.X))} | {EscapeCell(FormatCoordinate(item.Y))} | {EscapeCell(FormatCoordinate(item.Z))} | {EscapeCell(item.SetPositionResult)} | {EscapeCell(item.SetValueTextResult)} | {EscapeCell(item.SetValueImageResult)} | {EscapeCell(item.CounterKeyResult)} | {EscapeCell(item.Detail)} |");
|
|
}
|
|
}
|
|
|
|
static string EscapeCell(string? value)
|
|
{
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return value.Replace("\\", "\\\\", StringComparison.Ordinal)
|
|
.Replace("|", "\\|", StringComparison.Ordinal)
|
|
.Replace("\r", " ", StringComparison.Ordinal)
|
|
.Replace("\n", "<br/>", StringComparison.Ordinal);
|
|
}
|
|
|
|
static string EscapeInline(string? value) => EscapeCell(value);
|
|
|
|
static string FormatCoordinate(float? value) => value.HasValue ? value.Value.ToString("0.###") : string.Empty;
|
|
|
|
static Task<SdkProbeResult> ProbeSdkAsync(ProbeOptions options)
|
|
{
|
|
var completion = new TaskCompletionSource<SdkProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
try
|
|
{
|
|
var handler = new ProbeEventHandler();
|
|
var engine = (IKAEngine)new KAEngineClass();
|
|
|
|
Console.WriteLine("[SDK] Calling Connect()...");
|
|
var connectRequested = engine.Connect(options.Host, options.Port, handler);
|
|
Console.WriteLine($"[SDK] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}");
|
|
|
|
if (connectRequested == 0)
|
|
{
|
|
completion.TrySetResult(new SdkProbeResult(false, "FAILED", "Connect() returned 0."));
|
|
return;
|
|
}
|
|
|
|
if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Timeout))
|
|
{
|
|
completion.TrySetResult(new SdkProbeResult(true, "TIMEOUT", $"OnConnect was not received within {options.Timeout.TotalSeconds:0} seconds."));
|
|
return;
|
|
}
|
|
|
|
var errorCode = handler.ConnectTask.Result;
|
|
var outcome = errorCode == 0 ? "SUCCESS" : "FAILED";
|
|
completion.TrySetResult(new SdkProbeResult(true, outcome, $"OnConnect errorCode={errorCode}"));
|
|
|
|
try
|
|
{
|
|
engine.Disconnect();
|
|
handler.CloseTask.Wait(TimeSpan.FromSeconds(2));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
completion.TrySetResult(new SdkProbeResult(false, "EXCEPTION", ex.ToString()));
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "KarismaTcpProbe"
|
|
};
|
|
|
|
thread.SetApartmentState(ApartmentState.STA);
|
|
thread.Start();
|
|
return completion.Task;
|
|
}
|
|
|
|
static bool WaitForTaskWithMessagePump(Task task, TimeSpan timeout)
|
|
{
|
|
User32.PeekMessage(out _, IntPtr.Zero, 0, 0, 0);
|
|
|
|
var deadline = DateTime.UtcNow + timeout;
|
|
while (!task.IsCompleted)
|
|
{
|
|
while (User32.PeekMessage(out var message, IntPtr.Zero, 0, 0, 1))
|
|
{
|
|
User32.TranslateMessage(ref message);
|
|
User32.DispatchMessage(ref message);
|
|
}
|
|
|
|
if (DateTime.UtcNow >= deadline)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Thread.Sleep(10);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
internal sealed record ProbeOptions(string Host, int Port, TimeSpan Timeout)
|
|
{
|
|
public static ProbeOptions Parse(string[] args)
|
|
{
|
|
var host = "127.0.0.1";
|
|
var port = 30001;
|
|
var timeout = TimeSpan.FromSeconds(5);
|
|
|
|
for (var index = 0; index < args.Length; index++)
|
|
{
|
|
switch (args[index])
|
|
{
|
|
case "--host" when index + 1 < args.Length:
|
|
host = args[++index];
|
|
break;
|
|
case "--port" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedPort):
|
|
port = parsedPort;
|
|
index++;
|
|
break;
|
|
case "--timeout" when index + 1 < args.Length && double.TryParse(args[index + 1], out var parsedTimeoutSeconds):
|
|
timeout = TimeSpan.FromSeconds(parsedTimeoutSeconds);
|
|
index++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return new ProbeOptions(host, port, timeout);
|
|
}
|
|
}
|
|
|
|
internal sealed record CounterProbeOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string ObjectName,
|
|
int KeyIndex,
|
|
double Number)
|
|
{
|
|
public static CounterProbeOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? objectName = null;
|
|
var keyIndex = 1;
|
|
var number = 0d;
|
|
|
|
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 "--object" when index + 1 < args.Length:
|
|
objectName = args[++index];
|
|
break;
|
|
case "--key-index" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedKeyIndex):
|
|
keyIndex = parsedKeyIndex;
|
|
index++;
|
|
break;
|
|
case "--number" when index + 1 < args.Length && double.TryParse(args[index + 1], out var parsedNumber):
|
|
number = parsedNumber;
|
|
index++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(objectName))
|
|
{
|
|
throw new ArgumentException("--object is required.");
|
|
}
|
|
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
return new CounterProbeOptions(connection, scenePath, sceneAlias, objectName, keyIndex, number);
|
|
}
|
|
}
|
|
|
|
internal sealed record ChartInspectionOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string ObjectName)
|
|
{
|
|
public static ChartInspectionOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? objectName = null;
|
|
|
|
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 "--object" when index + 1 < args.Length:
|
|
objectName = args[++index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(objectName))
|
|
{
|
|
throw new ArgumentException("--object is required.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
return new ChartInspectionOptions(connection, scenePath, sceneAlias, objectName);
|
|
}
|
|
}
|
|
|
|
internal sealed record SaveSceneImageOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OutputPath,
|
|
int Width,
|
|
int Height,
|
|
int Frame,
|
|
IReadOnlyList<int> Frames,
|
|
string? OutputDirectory,
|
|
string OutputPattern,
|
|
string? SetObjectName,
|
|
string? SetObjectValue,
|
|
string? VisibleObjectName,
|
|
bool? VisibleObjectValue,
|
|
VariableNameUpdate? VariableName,
|
|
CloneObjectUpdate? CloneObject,
|
|
string? OperationsPath,
|
|
MaterialOpacityUpdate? MaterialOpacity,
|
|
SizeUpdate? Size,
|
|
PositionUpdate? Position,
|
|
IReadOnlyList<PositionUpdate> Positions,
|
|
PositionKeyUpdate? PositionKey,
|
|
IReadOnlyList<PositionKeyUpdate> PositionKeys,
|
|
IReadOnlyList<PositionUpdate> PostPositions,
|
|
IReadOnlyList<PositionKeyUpdate> PostPositionKeys,
|
|
string? ChartObjectName,
|
|
string? ChartCsvPath,
|
|
IReadOnlyList<ChartCellUpdate> ChartCells,
|
|
string? PathObjectName,
|
|
IReadOnlyList<PathPoint3> PathPoints,
|
|
IReadOnlyList<PathPointModification> PathModifications)
|
|
{
|
|
public static SaveSceneImageOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? outputPath = null;
|
|
string? outputDirectory = null;
|
|
string outputPattern = "frame_{0:D4}.png";
|
|
IReadOnlyList<int> frames = Array.Empty<int>();
|
|
string? setObjectName = null;
|
|
string? setObjectValue = null;
|
|
string? visibleObjectName = null;
|
|
bool? visibleObjectValue = null;
|
|
string? variableNameObjectName = null;
|
|
string? variableNameValue = null;
|
|
string? cloneSourceObjectName = null;
|
|
string? cloneVariableName = null;
|
|
string? operationsPath = null;
|
|
string? materialOpacityObjectName = null;
|
|
float? materialOpacityValue = null;
|
|
string? sizeObjectName = null;
|
|
string? sizeRaw = null;
|
|
string? positionObjectName = null;
|
|
string? positionRaw = null;
|
|
string? positionsRaw = null;
|
|
string? positionKeyObjectName = null;
|
|
int positionKeyIndex = 1;
|
|
string? positionKeyRaw = null;
|
|
string? positionKeysRaw = null;
|
|
string? postPositionsRaw = null;
|
|
string? postPositionKeysRaw = null;
|
|
string? chartObjectName = null;
|
|
string? chartCsvPath = null;
|
|
string? chartCellsRaw = null;
|
|
string? pathObjectName = null;
|
|
string? pathPointsRaw = null;
|
|
string? modifyPathRaw = 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 "--output-dir" when index + 1 < args.Length:
|
|
outputDirectory = args[++index];
|
|
break;
|
|
case "--output-pattern" when index + 1 < args.Length:
|
|
outputPattern = args[++index];
|
|
break;
|
|
case "--set-object" when index + 1 < args.Length:
|
|
setObjectName = args[++index];
|
|
break;
|
|
case "--set-value" when index + 1 < args.Length:
|
|
setObjectValue = args[++index];
|
|
break;
|
|
case "--visible-object" when index + 1 < args.Length:
|
|
visibleObjectName = args[++index];
|
|
break;
|
|
case "--visible" when index + 1 < args.Length:
|
|
visibleObjectValue = args[++index] switch
|
|
{
|
|
"1" or "true" or "True" => true,
|
|
"0" or "false" or "False" => false,
|
|
_ => throw new ArgumentException("--visible must be true/false/1/0.")
|
|
};
|
|
break;
|
|
case "--variable-name-object" when index + 1 < args.Length:
|
|
variableNameObjectName = args[++index];
|
|
break;
|
|
case "--variable-name" when index + 1 < args.Length:
|
|
variableNameValue = args[++index];
|
|
break;
|
|
case "--clone-source" when index + 1 < args.Length:
|
|
cloneSourceObjectName = args[++index];
|
|
break;
|
|
case "--clone-name" when index + 1 < args.Length:
|
|
cloneVariableName = args[++index];
|
|
break;
|
|
case "--operations" when index + 1 < args.Length:
|
|
operationsPath = args[++index];
|
|
break;
|
|
case "--material-opacity-object" when index + 1 < args.Length:
|
|
materialOpacityObjectName = args[++index];
|
|
break;
|
|
case "--material-opacity" when index + 1 < args.Length && float.TryParse(args[index + 1], out var parsedMaterialOpacity):
|
|
materialOpacityValue = parsedMaterialOpacity;
|
|
index++;
|
|
break;
|
|
case "--size-object" when index + 1 < args.Length:
|
|
sizeObjectName = args[++index];
|
|
break;
|
|
case "--size" when index + 1 < args.Length:
|
|
sizeRaw = args[++index];
|
|
break;
|
|
case "--position-object" when index + 1 < args.Length:
|
|
positionObjectName = args[++index];
|
|
break;
|
|
case "--position" when index + 1 < args.Length:
|
|
positionRaw = args[++index];
|
|
break;
|
|
case "--positions" when index + 1 < args.Length:
|
|
positionsRaw = args[++index];
|
|
break;
|
|
case "--position-key-object" when index + 1 < args.Length:
|
|
positionKeyObjectName = args[++index];
|
|
break;
|
|
case "--position-key-index" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedPositionKeyIndex):
|
|
positionKeyIndex = parsedPositionKeyIndex;
|
|
index++;
|
|
break;
|
|
case "--position-key" when index + 1 < args.Length:
|
|
positionKeyRaw = args[++index];
|
|
break;
|
|
case "--position-keys" when index + 1 < args.Length:
|
|
positionKeysRaw = args[++index];
|
|
break;
|
|
case "--post-positions" when index + 1 < args.Length:
|
|
postPositionsRaw = args[++index];
|
|
break;
|
|
case "--post-position-keys" when index + 1 < args.Length:
|
|
postPositionKeysRaw = args[++index];
|
|
break;
|
|
case "--chart-object" when index + 1 < args.Length:
|
|
chartObjectName = args[++index];
|
|
break;
|
|
case "--chart-csv" when index + 1 < args.Length:
|
|
chartCsvPath = args[++index];
|
|
break;
|
|
case "--chart-cells" when index + 1 < args.Length:
|
|
chartCellsRaw = args[++index];
|
|
break;
|
|
case "--path-object" when index + 1 < args.Length:
|
|
pathObjectName = args[++index];
|
|
break;
|
|
case "--path-points" when index + 1 < args.Length:
|
|
pathPointsRaw = args[++index];
|
|
break;
|
|
case "--modify-path" when index + 1 < args.Length:
|
|
modifyPathRaw = 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;
|
|
case "--frames" when index + 1 < args.Length:
|
|
frames = ParseFrameSequence(args[++index]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (frames.Count > 0)
|
|
{
|
|
outputDirectory ??= outputPath;
|
|
if (string.IsNullOrWhiteSpace(outputDirectory))
|
|
{
|
|
throw new ArgumentException("--output-dir is required when --frames is provided.");
|
|
}
|
|
|
|
outputDirectory = Path.GetFullPath(outputDirectory);
|
|
outputPath ??= outputDirectory;
|
|
}
|
|
else if (string.IsNullOrWhiteSpace(outputPath))
|
|
{
|
|
throw new ArgumentException("--output is required.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
operationsPath = string.IsNullOrWhiteSpace(operationsPath)
|
|
? null
|
|
: Path.GetFullPath(operationsPath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
return new SaveSceneImageOptions(
|
|
connection,
|
|
scenePath,
|
|
sceneAlias,
|
|
outputPath,
|
|
width,
|
|
height,
|
|
frame,
|
|
frames,
|
|
outputDirectory,
|
|
outputPattern,
|
|
setObjectName,
|
|
setObjectValue,
|
|
visibleObjectName,
|
|
visibleObjectValue,
|
|
ParseVariableName(variableNameObjectName, variableNameValue),
|
|
ParseCloneObject(cloneSourceObjectName, cloneVariableName),
|
|
operationsPath,
|
|
ParseMaterialOpacity(materialOpacityObjectName, materialOpacityValue),
|
|
ParseSize(sizeObjectName, sizeRaw),
|
|
ParsePosition(positionObjectName, positionRaw),
|
|
ParsePositions(positionsRaw),
|
|
ParsePositionKey(positionKeyObjectName, positionKeyIndex, positionKeyRaw),
|
|
ParsePositionKeys(positionKeysRaw),
|
|
ParsePositions(postPositionsRaw),
|
|
ParsePositionKeys(postPositionKeysRaw),
|
|
chartObjectName,
|
|
chartCsvPath,
|
|
ParseChartCells(chartCellsRaw),
|
|
pathObjectName,
|
|
ParsePathPoints(pathPointsRaw),
|
|
ParsePathModifications(modifyPathRaw));
|
|
}
|
|
|
|
private static IReadOnlyList<int> ParseFrameSequence(string value)
|
|
{
|
|
var frames = new List<int>();
|
|
foreach (var token in value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var rangeMatch = Regex.Match(token, @"^(?<start>-?\d+)-(?<end>-?\d+)(?::(?<step>\d+))?$", RegexOptions.CultureInvariant);
|
|
if (rangeMatch.Success)
|
|
{
|
|
var start = int.Parse(rangeMatch.Groups["start"].Value, CultureInfo.InvariantCulture);
|
|
var end = int.Parse(rangeMatch.Groups["end"].Value, CultureInfo.InvariantCulture);
|
|
var step = rangeMatch.Groups["step"].Success
|
|
? int.Parse(rangeMatch.Groups["step"].Value, CultureInfo.InvariantCulture)
|
|
: 1;
|
|
if (step <= 0)
|
|
{
|
|
throw new ArgumentException("--frames range step must be greater than zero.");
|
|
}
|
|
|
|
if (start <= end)
|
|
{
|
|
for (var frame = start; frame <= end; frame += step)
|
|
{
|
|
frames.Add(frame);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var frame = start; frame >= end; frame -= step)
|
|
{
|
|
frames.Add(frame);
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out var singleFrame))
|
|
{
|
|
throw new ArgumentException($"Invalid frame token: {token}");
|
|
}
|
|
|
|
frames.Add(singleFrame);
|
|
}
|
|
|
|
return frames.Distinct().ToArray();
|
|
}
|
|
|
|
private static CloneObjectUpdate? ParseCloneObject(string? sourceObjectName, string? variableName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(sourceObjectName) || string.IsNullOrWhiteSpace(variableName))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new CloneObjectUpdate(sourceObjectName, variableName);
|
|
}
|
|
|
|
private static MaterialOpacityUpdate? ParseMaterialOpacity(string? objectName, float? opacity)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(objectName) || !opacity.HasValue)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new MaterialOpacityUpdate(objectName, opacity.Value);
|
|
}
|
|
|
|
private static VariableNameUpdate? ParseVariableName(string? objectName, string? variableName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(objectName) || string.IsNullOrWhiteSpace(variableName))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new VariableNameUpdate(objectName, variableName);
|
|
}
|
|
|
|
private static SizeUpdate? ParseSize(string? objectName, string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(objectName) || string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var parts = raw.Split(',', StringSplitOptions.TrimEntries);
|
|
if (parts.Length != 2 ||
|
|
!float.TryParse(parts[0], out var width) ||
|
|
!float.TryParse(parts[1], out var height))
|
|
{
|
|
throw new ArgumentException("--size must be 'width,height'.");
|
|
}
|
|
|
|
return new SizeUpdate(objectName, width, height);
|
|
}
|
|
|
|
private static PositionUpdate? ParsePosition(string? objectName, string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(objectName) || string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var vectorType = eKVectorType.VECTOR_TYPE_XYZ;
|
|
var rawParts = raw.Split(':', StringSplitOptions.TrimEntries);
|
|
var coordinatesRaw = rawParts[0];
|
|
if (rawParts.Length > 1 && !Enum.TryParse(rawParts[1], true, out vectorType))
|
|
{
|
|
throw new ArgumentException($"Unknown vector type '{rawParts[1]}'.");
|
|
}
|
|
|
|
var coordinates = coordinatesRaw.Split(',', StringSplitOptions.TrimEntries);
|
|
if (coordinates.Length < 2 ||
|
|
!float.TryParse(coordinates[0], out var x) ||
|
|
!float.TryParse(coordinates[1], out var y))
|
|
{
|
|
throw new ArgumentException("--position must be 'x,y[,z][:VectorType]'.");
|
|
}
|
|
|
|
var z = 0f;
|
|
if (coordinates.Length > 2 && !float.TryParse(coordinates[2], out z))
|
|
{
|
|
throw new ArgumentException("--position z must be numeric.");
|
|
}
|
|
|
|
return new PositionUpdate(objectName, x, y, z, vectorType);
|
|
}
|
|
|
|
private static IReadOnlyList<PositionUpdate> ParsePositions(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return Array.Empty<PositionUpdate>();
|
|
}
|
|
|
|
var updates = new List<PositionUpdate>();
|
|
foreach (var token in raw.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var nameParts = token.Split('=', 2, StringSplitOptions.TrimEntries);
|
|
if (nameParts.Length != 2)
|
|
{
|
|
throw new ArgumentException($"Invalid position update: {token}");
|
|
}
|
|
|
|
var update = ParsePosition(nameParts[0], nameParts[1]);
|
|
if (update is not null)
|
|
{
|
|
updates.Add(update);
|
|
}
|
|
}
|
|
|
|
return updates;
|
|
}
|
|
|
|
private static PositionKeyUpdate? ParsePositionKey(string? objectName, int keyIndex, string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(objectName) || string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var vectorType = eKVectorType.VECTOR_TYPE_XYZ;
|
|
var rawParts = raw.Split(':', StringSplitOptions.TrimEntries);
|
|
var coordinatesRaw = rawParts[0];
|
|
if (rawParts.Length > 1 && !Enum.TryParse(rawParts[1], true, out vectorType))
|
|
{
|
|
throw new ArgumentException($"Unknown vector type '{rawParts[1]}'.");
|
|
}
|
|
|
|
var coordinates = coordinatesRaw.Split(',', StringSplitOptions.TrimEntries);
|
|
if (coordinates.Length < 2 ||
|
|
!float.TryParse(coordinates[0], out var x) ||
|
|
!float.TryParse(coordinates[1], out var y))
|
|
{
|
|
throw new ArgumentException("--position-key must be 'x,y[,z][:VectorType]'.");
|
|
}
|
|
|
|
var z = 0f;
|
|
if (coordinates.Length > 2 && !float.TryParse(coordinates[2], out z))
|
|
{
|
|
throw new ArgumentException("--position-key z must be numeric.");
|
|
}
|
|
|
|
return new PositionKeyUpdate(objectName, keyIndex, x, y, z, vectorType);
|
|
}
|
|
|
|
private static IReadOnlyList<PositionKeyUpdate> ParsePositionKeys(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return Array.Empty<PositionKeyUpdate>();
|
|
}
|
|
|
|
var updates = new List<PositionKeyUpdate>();
|
|
foreach (var token in raw.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var nameParts = token.Split('=', 2, StringSplitOptions.TrimEntries);
|
|
if (nameParts.Length != 2)
|
|
{
|
|
throw new ArgumentException($"Invalid position key update: {token}");
|
|
}
|
|
|
|
var objectAndKey = nameParts[0].Split('#', 2, StringSplitOptions.TrimEntries);
|
|
if (objectAndKey.Length != 2 || !int.TryParse(objectAndKey[1], out var keyIndex))
|
|
{
|
|
throw new ArgumentException($"Invalid position key object/index: {nameParts[0]}");
|
|
}
|
|
|
|
var update = ParsePositionKey(objectAndKey[0], keyIndex, nameParts[1]);
|
|
if (update is not null)
|
|
{
|
|
updates.Add(update);
|
|
}
|
|
}
|
|
|
|
return updates;
|
|
}
|
|
|
|
private static IReadOnlyList<ChartCellUpdate> ParseChartCells(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return Array.Empty<ChartCellUpdate>();
|
|
}
|
|
|
|
var updates = new List<ChartCellUpdate>();
|
|
foreach (var token in raw.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var parts = token.Split(',', StringSplitOptions.TrimEntries);
|
|
if (parts.Length < 3 ||
|
|
!int.TryParse(parts[0], out var row) ||
|
|
!int.TryParse(parts[1], out var column) ||
|
|
!float.TryParse(parts[2], out var value))
|
|
{
|
|
throw new ArgumentException($"Invalid chart cell update: {token}");
|
|
}
|
|
|
|
updates.Add(new ChartCellUpdate(row, column, value));
|
|
}
|
|
|
|
return updates;
|
|
}
|
|
|
|
private static IReadOnlyList<PathPoint3> ParsePathPoints(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return Array.Empty<PathPoint3>();
|
|
}
|
|
|
|
var points = new List<PathPoint3>();
|
|
foreach (var token in raw.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var parts = token.Split(',', StringSplitOptions.TrimEntries);
|
|
if (parts.Length < 2 ||
|
|
!float.TryParse(parts[0], out var x) ||
|
|
!float.TryParse(parts[1], out var y))
|
|
{
|
|
throw new ArgumentException($"Invalid path point: {token}");
|
|
}
|
|
|
|
var z = 0f;
|
|
if (parts.Length >= 3 && !float.TryParse(parts[2], out z))
|
|
{
|
|
throw new ArgumentException($"Invalid path point z value: {token}");
|
|
}
|
|
|
|
points.Add(new PathPoint3(x, y, z));
|
|
}
|
|
|
|
return points;
|
|
}
|
|
|
|
private static IReadOnlyList<PathPointModification> ParsePathModifications(string? raw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
{
|
|
return Array.Empty<PathPointModification>();
|
|
}
|
|
|
|
var modifications = new List<PathPointModification>();
|
|
foreach (var token in raw.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
{
|
|
var sections = token.Split(':', StringSplitOptions.TrimEntries);
|
|
if (sections.Length < 2)
|
|
{
|
|
throw new ArgumentException($"Invalid path modification: {token}");
|
|
}
|
|
|
|
if (!int.TryParse(sections[0], out var index))
|
|
{
|
|
throw new ArgumentException($"Invalid path modification index: {token}");
|
|
}
|
|
|
|
var coords = sections[1].Split(',', StringSplitOptions.TrimEntries);
|
|
if (coords.Length < 2 ||
|
|
!float.TryParse(coords[0], out var x) ||
|
|
!float.TryParse(coords[1], out var y))
|
|
{
|
|
throw new ArgumentException($"Invalid path modification coordinates: {token}");
|
|
}
|
|
|
|
var z = 0f;
|
|
if (coords.Length >= 3 && !float.TryParse(coords[2], out z))
|
|
{
|
|
throw new ArgumentException($"Invalid path modification z value: {token}");
|
|
}
|
|
|
|
var vectorType = eKVectorType.VECTOR_TYPE_XYZ;
|
|
if (sections.Length >= 3)
|
|
{
|
|
vectorType = sections[2].ToUpperInvariant() switch
|
|
{
|
|
"X" => eKVectorType.VECTOR_TYPE_X,
|
|
"Y" => eKVectorType.VECTOR_TYPE_Y,
|
|
"Z" => eKVectorType.VECTOR_TYPE_Z,
|
|
"XY" => eKVectorType.VECTOR_TYPE_XY,
|
|
"YZ" => eKVectorType.VECTOR_TYPE_YZ,
|
|
"ZX" => eKVectorType.VECTOR_TYPE_ZX,
|
|
"XYZ" => eKVectorType.VECTOR_TYPE_XYZ,
|
|
_ => throw new ArgumentException($"Invalid path modification vector type: {token}")
|
|
};
|
|
}
|
|
|
|
modifications.Add(new PathPointModification(index, x, y, z, vectorType));
|
|
}
|
|
|
|
return modifications;
|
|
}
|
|
}
|
|
|
|
internal sealed record SceneCatalogOptions(
|
|
ProbeOptions Connection,
|
|
string RootPath,
|
|
string OutputPath,
|
|
string? SceneFilter,
|
|
int? MaxScenes)
|
|
{
|
|
public static SceneCatalogOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
var rootPath = TornadoPathResolver.GetDefaultT3CutPath();
|
|
string? outputPath = null;
|
|
string? sceneFilter = null;
|
|
int? maxScenes = null;
|
|
|
|
for (var index = 0; index < args.Length; index++)
|
|
{
|
|
switch (args[index])
|
|
{
|
|
case "--root" when index + 1 < args.Length:
|
|
rootPath = args[++index];
|
|
break;
|
|
case "--output" when index + 1 < args.Length:
|
|
outputPath = args[++index];
|
|
break;
|
|
case "--filter" when index + 1 < args.Length:
|
|
sceneFilter = args[++index];
|
|
break;
|
|
case "--max-scenes" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedMaxScenes):
|
|
maxScenes = parsedMaxScenes;
|
|
index++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Directory.Exists(rootPath))
|
|
{
|
|
throw new DirectoryNotFoundException($"Catalog root path does not exist: {rootPath}");
|
|
}
|
|
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "SCENE_OBJECT_CATALOG.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new SceneCatalogOptions(connection, Path.GetFullPath(rootPath), outputPath, sceneFilter, maxScenes);
|
|
}
|
|
}
|
|
|
|
internal sealed record SceneObjectInspectionOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OutputPath,
|
|
string? NameFilter)
|
|
{
|
|
public static SceneObjectInspectionOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? outputPath = null;
|
|
string? nameFilter = null;
|
|
|
|
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 "--filter" when index + 1 < args.Length:
|
|
nameFilter = args[++index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "SCENE_OBJECT_INSPECTION.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new SceneObjectInspectionOptions(connection, scenePath, sceneAlias, outputPath, nameFilter);
|
|
}
|
|
}
|
|
|
|
internal sealed record ObjectTypeQueryOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OutputPath,
|
|
IReadOnlyList<string> ObjectNames)
|
|
{
|
|
public static ObjectTypeQueryOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? outputPath = null;
|
|
string? objectsRaw = null;
|
|
|
|
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 "--objects" when index + 1 < args.Length:
|
|
objectsRaw = args[++index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(objectsRaw))
|
|
{
|
|
throw new ArgumentException("--objects is required.");
|
|
}
|
|
|
|
var objectNames = objectsRaw
|
|
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.ToArray();
|
|
if (objectNames.Length == 0)
|
|
{
|
|
throw new ArgumentException("--objects did not contain any names.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "OBJECT_TYPE_QUERY.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new ObjectTypeQueryOptions(connection, scenePath, sceneAlias, outputPath, objectNames);
|
|
}
|
|
}
|
|
|
|
internal sealed record ScreenPointInspectionOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OutputPath,
|
|
IReadOnlyList<ScreenPoint> Points)
|
|
{
|
|
public static ScreenPointInspectionOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? outputPath = null;
|
|
string? pointsRaw = null;
|
|
|
|
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 "--points" when index + 1 < args.Length:
|
|
pointsRaw = args[++index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(pointsRaw))
|
|
{
|
|
throw new ArgumentException("--points is required.");
|
|
}
|
|
|
|
var points = pointsRaw
|
|
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.Select(rawPoint =>
|
|
{
|
|
var coordinates = rawPoint.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
if (coordinates.Length != 2 ||
|
|
!int.TryParse(coordinates[0], out var x) ||
|
|
!int.TryParse(coordinates[1], out var y))
|
|
{
|
|
throw new ArgumentException($"Invalid screen point '{rawPoint}'. Use 'x,y'.");
|
|
}
|
|
|
|
return new ScreenPoint(x, y);
|
|
})
|
|
.Distinct()
|
|
.ToArray();
|
|
if (points.Length == 0)
|
|
{
|
|
throw new ArgumentException("--points did not contain any coordinates.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "SCREEN_POINT_INSPECTION.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new ScreenPointInspectionOptions(connection, scenePath, sceneAlias, outputPath, points);
|
|
}
|
|
}
|
|
|
|
internal sealed record SceneCapabilityInspectionOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OutputPath,
|
|
IReadOnlyList<string> Keywords,
|
|
int? MaxCandidates)
|
|
{
|
|
public static SceneCapabilityInspectionOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? outputPath = null;
|
|
string? keywordsRaw = null;
|
|
int? maxCandidates = null;
|
|
|
|
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 "--keywords" when index + 1 < args.Length:
|
|
keywordsRaw = args[++index];
|
|
break;
|
|
case "--max-candidates" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedMaxCandidates):
|
|
maxCandidates = parsedMaxCandidates;
|
|
index++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
var keywords = string.IsNullOrWhiteSpace(keywordsRaw)
|
|
? Array.Empty<string>()
|
|
: keywordsRaw
|
|
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.ToArray();
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "SCENE_CAPABILITY_INSPECTION.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new SceneCapabilityInspectionOptions(connection, scenePath, sceneAlias, outputPath, keywords, maxCandidates);
|
|
}
|
|
}
|
|
|
|
internal sealed record SceneValidationOptions(
|
|
ProbeOptions Connection,
|
|
string ScenePath,
|
|
string SceneAlias,
|
|
string OperationsPath,
|
|
string OutputPath)
|
|
{
|
|
public static SceneValidationOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
string? scenePath = null;
|
|
string? sceneAlias = null;
|
|
string? operationsPath = null;
|
|
string? outputPath = null;
|
|
|
|
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 "--operations" when index + 1 < args.Length:
|
|
operationsPath = args[++index];
|
|
break;
|
|
case "--output" when index + 1 < args.Length:
|
|
outputPath = args[++index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(scenePath))
|
|
{
|
|
throw new ArgumentException("--scene is required.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(operationsPath))
|
|
{
|
|
throw new ArgumentException("--operations is required.");
|
|
}
|
|
|
|
scenePath = Path.GetFullPath(scenePath);
|
|
operationsPath = Path.GetFullPath(operationsPath);
|
|
sceneAlias ??= Path.GetFileNameWithoutExtension(scenePath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "SCENE_VARIABLE_VALIDATION.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
|
|
return new SceneValidationOptions(connection, scenePath, sceneAlias, operationsPath, outputPath);
|
|
}
|
|
}
|
|
|
|
internal sealed record FolderInspectionOptions(ProbeOptions Connection, string RootPath, string OutputPath, string? SceneFilter, int? MaxScenes)
|
|
{
|
|
public static FolderInspectionOptions Parse(string[] args)
|
|
{
|
|
var connection = ProbeOptions.Parse(args);
|
|
var rootPath = TornadoPathResolver.GetDefaultT3CutPath();
|
|
string? outputPath = null;
|
|
string? sceneFilter = null;
|
|
int? maxScenes = null;
|
|
|
|
for (var index = 0; index < args.Length; index++)
|
|
{
|
|
switch (args[index])
|
|
{
|
|
case "--root" when index + 1 < args.Length:
|
|
rootPath = args[++index];
|
|
break;
|
|
case "--output" when index + 1 < args.Length:
|
|
outputPath = args[++index];
|
|
break;
|
|
case "--filter" when index + 1 < args.Length:
|
|
sceneFilter = args[++index];
|
|
break;
|
|
case "--max-scenes" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedMaxScenes):
|
|
maxScenes = parsedMaxScenes;
|
|
index++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
rootPath = Path.GetFullPath(rootPath);
|
|
outputPath ??= Path.Combine(Environment.CurrentDirectory, "TSCN_VARIABLE_DISCOVERY.md");
|
|
outputPath = Path.GetFullPath(outputPath);
|
|
return new FolderInspectionOptions(connection, rootPath, outputPath, sceneFilter, maxScenes);
|
|
}
|
|
}
|
|
|
|
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 ChartCellSnapshot(int Row, int Column, string Value);
|
|
internal sealed record ChartCellUpdate(int Row, int Column, float Value);
|
|
internal sealed record PathPoint3(float X, float Y, float Z);
|
|
internal sealed record SizeUpdate(string ObjectName, float Width, float Height);
|
|
internal sealed record VariableNameUpdate(string ObjectName, string VariableName);
|
|
internal sealed record CloneObjectUpdate(string SourceObjectName, string VariableName);
|
|
internal sealed record MaterialOpacityUpdate(string ObjectName, float Opacity);
|
|
internal sealed record PositionUpdate(string ObjectName, float X, float Y, float Z, eKVectorType VectorType);
|
|
internal sealed record PositionKeyUpdate(string ObjectName, int KeyIndex, float X, float Y, float Z, eKVectorType VectorType);
|
|
internal sealed record PathPointModification(int Index, float X, float Y, float Z, eKVectorType VectorType);
|
|
internal sealed record ChartDataTableProbeResult(
|
|
eKResult Result,
|
|
int RowCount,
|
|
int ColumnCount,
|
|
IReadOnlyList<ChartCellSnapshot> Cells,
|
|
string Detail);
|
|
internal sealed record ChartInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string InspectionOutcome,
|
|
int RowCount,
|
|
int ColumnCount,
|
|
IReadOnlyList<ChartCellSnapshot> Cells,
|
|
string Detail);
|
|
internal sealed record SaveSceneImageProbeResult(bool ConnectRequestAccepted, string SceneLoadOutcome, string SaveOutcome, string OutputPath, string Detail);
|
|
internal sealed record SceneCatalogProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
int SceneCount,
|
|
int CatalogedCount,
|
|
string OutputPath,
|
|
IReadOnlyList<SceneCatalogFailure> Failures);
|
|
internal sealed record SceneCatalogFailure(string ScenePath, string Reason);
|
|
internal sealed record SceneCatalogEntry(string ScenePath, string RelativePath, IReadOnlyList<SceneObjectCatalogItem> Objects);
|
|
internal sealed record SceneObjectCatalogItem(string Name, eKObjectType ObjectType, string Value, bool Visible);
|
|
internal sealed record ObjectInfosProbeResult(eKResult Result, string SceneName, IReadOnlyList<SceneObjectCatalogItem> Objects, string Detail);
|
|
internal sealed record SceneObjectInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string ObjectInfoOutcome,
|
|
string OutputPath,
|
|
IReadOnlyList<SceneObjectCatalogItem> Objects,
|
|
string Detail);
|
|
internal sealed record ObjectTypeCallbackResult(eKResult Result, string ObjectName, eKObjectType ObjectType, string Detail);
|
|
internal sealed record ObjectTypeQueryItem(string ObjectName, string Result, eKObjectType ObjectType, string Detail);
|
|
internal sealed record ObjectTypeQueryProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string OutputPath,
|
|
IReadOnlyList<ObjectTypeQueryItem> Items,
|
|
string Detail);
|
|
internal sealed record PositionCallbackResult(eKResult Result, string ObjectName, float X, float Y, float Z, string Detail);
|
|
internal sealed record ScreenPoint(int X, int Y);
|
|
internal sealed record ScreenPointInspectionItem(int X, int Y, string Result, IReadOnlyList<SceneObjectCatalogItem> Objects, string Detail);
|
|
internal sealed record ScreenPointInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string OutputPath,
|
|
IReadOnlyList<ScreenPointInspectionItem> Items,
|
|
string Detail);
|
|
internal sealed record SceneCapabilityInspectionItem(
|
|
string Candidate,
|
|
bool ObjectFound,
|
|
string AnimationName,
|
|
bool IsChart,
|
|
bool IsCounter,
|
|
bool IsPath,
|
|
string QueryTypeResult,
|
|
eKObjectType ObjectType,
|
|
string QueryPositionResult,
|
|
float? X,
|
|
float? Y,
|
|
float? Z,
|
|
string SetPositionResult,
|
|
string SetValueTextResult,
|
|
string SetValueImageResult,
|
|
string CounterKeyResult,
|
|
string Detail);
|
|
internal sealed record SceneCapabilityInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string OutputPath,
|
|
IReadOnlyList<SceneCapabilityInspectionItem> Items,
|
|
string Detail);
|
|
internal sealed record ObjectRuntimeInspectionItem(
|
|
string ObjectName,
|
|
string TypeResult,
|
|
eKObjectType ObjectType,
|
|
string AnimationName,
|
|
string PositionResult,
|
|
float? X,
|
|
float? Y,
|
|
float? Z,
|
|
string Detail);
|
|
internal sealed record ObjectRuntimeInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
string OutputPath,
|
|
IReadOnlyList<ObjectRuntimeInspectionItem> Items,
|
|
string Detail);
|
|
internal sealed record SceneValidationProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
string SceneLoadOutcome,
|
|
int SuccessCount,
|
|
int FailureCount,
|
|
string OutputPath,
|
|
string Detail);
|
|
internal sealed record FolderInspectionProbeResult(
|
|
bool ConnectRequestAccepted,
|
|
int SceneCount,
|
|
int ProcessedSceneCount,
|
|
int DiscoveredVariableCount,
|
|
int FailureCount,
|
|
string OutputPath,
|
|
string Detail);
|
|
internal sealed class SceneValidationOperation
|
|
{
|
|
public string ObjectName { get; set; } = string.Empty;
|
|
|
|
public string Method { get; set; } = "SetValue";
|
|
|
|
public string? Value { get; set; }
|
|
|
|
public int KeyIndex { get; set; }
|
|
|
|
public double Number { get; set; }
|
|
|
|
public string? StyleType { get; set; }
|
|
|
|
public int Order { get; set; }
|
|
|
|
public int R { get; set; }
|
|
|
|
public int G { get; set; }
|
|
|
|
public int B { get; set; }
|
|
|
|
public int A { get; set; } = 255;
|
|
|
|
public bool Visible { get; set; }
|
|
|
|
public bool ContinueOnFailure { get; set; }
|
|
}
|
|
|
|
internal sealed record SceneOperationValidationResult(string ObjectName, string Method, string Payload, string Result, string Detail);
|
|
internal sealed record SceneInspectionResult(string ScenePath, string RelativePath, int CandidateCount, IReadOnlyList<SceneVariableDiscovery> Discoveries);
|
|
internal sealed record SceneVariableDiscovery(string VariableName, string Method, string Payload, string Result);
|
|
|
|
internal sealed class ProbeEventHandler : KAEventHandler
|
|
{
|
|
private readonly TaskCompletionSource<int> _connectTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private readonly TaskCompletionSource<int> _closeTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _loadSceneTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _unloadSceneTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _counterNumberKeyTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _styleColorTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _visibleTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _variableNameTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _addCloneObjectTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _materialOpacityTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _setValueTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _sizeTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _saveSceneImageTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<ObjectInfosProbeResult> _objectInfosTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<ChartDataTableProbeResult> _chartDataTableTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _chartMutationTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<ObjectTypeCallbackResult> _objectTypeTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<PositionCallbackResult> _queryPositionTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _positionTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _positionKeyTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private TaskCompletionSource<eKResult> _pathPointTask = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
private IKAScene? _sceneToQueryOnLoad;
|
|
|
|
public Task<int> ConnectTask => _connectTask.Task;
|
|
|
|
public Task<int> CloseTask => _closeTask.Task;
|
|
|
|
public Task<eKResult> LoadSceneTask => _loadSceneTask.Task;
|
|
|
|
public Task<eKResult> UnloadSceneTask => _unloadSceneTask.Task;
|
|
|
|
public Task<eKResult> CounterNumberKeyTask => _counterNumberKeyTask.Task;
|
|
|
|
public Task<eKResult> StyleColorTask => _styleColorTask.Task;
|
|
|
|
public Task<eKResult> VisibleTask => _visibleTask.Task;
|
|
|
|
public Task<eKResult> VariableNameTask => _variableNameTask.Task;
|
|
|
|
public Task<eKResult> AddCloneObjectTask => _addCloneObjectTask.Task;
|
|
|
|
public Task<eKResult> MaterialOpacityTask => _materialOpacityTask.Task;
|
|
|
|
public Task<eKResult> SetValueTask => _setValueTask.Task;
|
|
|
|
public Task<eKResult> SizeTask => _sizeTask.Task;
|
|
|
|
public Task<eKResult> SaveSceneImageTask => _saveSceneImageTask.Task;
|
|
|
|
public Task<ObjectInfosProbeResult> ObjectInfosTask => _objectInfosTask.Task;
|
|
|
|
public Task<ChartDataTableProbeResult> ChartDataTableTask => _chartDataTableTask.Task;
|
|
|
|
public Task<eKResult> ChartMutationTask => _chartMutationTask.Task;
|
|
|
|
public Task<ObjectTypeCallbackResult> ObjectTypeTask => _objectTypeTask.Task;
|
|
|
|
public Task<PositionCallbackResult> QueryPositionTask => _queryPositionTask.Task;
|
|
|
|
public Task<eKResult> PositionTask => _positionTask.Task;
|
|
|
|
public Task<eKResult> PositionKeyTask => _positionKeyTask.Task;
|
|
|
|
public Task<eKResult> PathPointTask => _pathPointTask.Task;
|
|
|
|
public void ResetLoadSceneTask() => _loadSceneTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetUnloadSceneTask() => _unloadSceneTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetCounterNumberKeyTask() => _counterNumberKeyTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetStyleColorTask() => _styleColorTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetVisibleTask() => _visibleTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetVariableNameTask() => _variableNameTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetAddCloneObjectTask() => _addCloneObjectTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetMaterialOpacityTask() => _materialOpacityTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetSetValueTask() => _setValueTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetSizeTask() => _sizeTask = 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 ResetChartDataTableTask() => _chartDataTableTask = new TaskCompletionSource<ChartDataTableProbeResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetChartMutationTask() => _chartMutationTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetObjectTypeTask() => _objectTypeTask = new TaskCompletionSource<ObjectTypeCallbackResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetQueryPositionTask() => _queryPositionTask = new TaskCompletionSource<PositionCallbackResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetPositionTask() => _positionTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetPositionKeyTask() => _positionKeyTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ResetPathPointTask() => _pathPointTask = new TaskCompletionSource<eKResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
|
|
public void ConfigureQueryObjectInfosOnLoad(IKAScene scene) => _sceneToQueryOnLoad = scene;
|
|
|
|
public void OnConnect(int ErrorCode)
|
|
{
|
|
Console.WriteLine($"[SDK] OnConnect errorCode={ErrorCode}");
|
|
_connectTask.TrySetResult(ErrorCode);
|
|
}
|
|
|
|
public void OnClose(int ErrorCode)
|
|
{
|
|
Console.WriteLine($"[SDK] OnClose errorCode={ErrorCode}");
|
|
_closeTask.TrySetResult(ErrorCode);
|
|
}
|
|
|
|
public void OnLoadScene(eKResult Result, string SceneName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnLoadScene result={Result} scene={SceneName}");
|
|
_loadSceneTask.TrySetResult(Result);
|
|
|
|
if (Result == eKResult.RESULT_SUCCESS && _sceneToQueryOnLoad is not null)
|
|
{
|
|
try
|
|
{
|
|
_sceneToQueryOnLoad.QueryObjectInfos();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_objectInfosTask.TrySetResult(new ObjectInfosProbeResult(
|
|
eKResult.RESULT_FAILURE,
|
|
SceneName,
|
|
Array.Empty<SceneObjectCatalogItem>(),
|
|
ex.Message));
|
|
}
|
|
finally
|
|
{
|
|
_sceneToQueryOnLoad = null;
|
|
}
|
|
}
|
|
}
|
|
public void OnLoadSceneForce(eKResult Result, string SceneName) { }
|
|
public void OnLogMessage(string LogMessage) { }
|
|
public void OnMessageNo(uint MessageNo) { }
|
|
public void OnBeginTransaction(eKResult Result) { }
|
|
public void OnEndTransaction(eKResult Result) { }
|
|
public void OnHeartBeat(eKResult Result) { }
|
|
public void OnUnloadAll(eKResult Result) { }
|
|
public void OnSetTrialPlayoutMode(eKResult Result) { }
|
|
public void OnCheckVersion(eKResult Result, string ServerVersion, string SDKVersion) { }
|
|
public void OnSetAudioOutput(eKResult Result) { }
|
|
public void OnScenePrepare(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnScenePrepareEx(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnPlay(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnPlayOut(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnStop(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnStopAll(eKResult Result) { }
|
|
public void OnPause(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnResume(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnQueryIsOnAir(eKResult Result, int OutputChannelIndex, int LayerNo, int bOnAir) { }
|
|
public void OnTrigger(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnScenePlayingStarted(string SceneName, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnScenePlayed(string SceneName, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnSceneAnimationPlayed(string SceneName, int OutputChannelIndex, int LayerNo, string AnimationName) { }
|
|
public void OnScenePaused(string SceneName, int OutputChannelIndex, int LayerNo, int bLastPause) { }
|
|
public void OnSceneSaved(eKResult Result, string FileName) { }
|
|
public void OnTriggerObject(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnResumeBackground(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnSaveMixedPreviewImage(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnPlayDirect(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnCutIn(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnCutOut(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnClearNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnPlayRange(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnQueryPlaybackRangeCount(eKResult Result, string SceneName, int PlaybackRangeCount) { }
|
|
public void OnQueryPlaybackRange(eKResult Result, string SceneName, int PlaybackRangeNo, int Start, int End) { }
|
|
public void OnQueryOutputChannelIndex(eKResult Result, string SceneName, int OutputChannelIndex) { }
|
|
public void OnPlayInNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnPlayOutNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnSetBackgroundFill(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundTexture(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundVideo(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundLiveIn(eKResult Result, string SceneName) { }
|
|
public void OnUseBackground(eKResult Result, string SceneName) { }
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
_unloadSceneTask.TrySetResult(Result);
|
|
}
|
|
public void OnReloadScene(eKResult Result, string SceneName) { }
|
|
public void OnUpdateTextures(eKResult Result, string SceneName) { }
|
|
public void OnSetSceneAudioFile(eKResult Result, string SceneName) { }
|
|
public void OnEnableSceneAudio(eKResult Result, string SceneName) { }
|
|
public void OnSetSceneDuration(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundPauseType(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundChangeType(eKResult Result, string SceneName) { }
|
|
public void OnSetBackgroundPauseAtZeroFrameAsStandBy(eKResult Result, string SceneName) { }
|
|
public void OnResetDuration(eKResult Result, string SceneName) { }
|
|
public void OnSetDuration(eKResult Result, string SceneName) { }
|
|
public void OnAddObject(eKResult Result, string SceneName) { }
|
|
public void OnUpdateThumbnail(eKResult Result, string SceneName) { }
|
|
public void OnExportVideo(eKResult Result, string SceneName) { }
|
|
public void OnStopVideoExporting(eKResult Result) { }
|
|
public void OnQueryVideoExportingProgress(eKResult Result, string TargetName, int CurrentFrame, int TotalFrame) { }
|
|
public void OnFinishedVideoExporting(eKResult Result, string FileName) { }
|
|
public void OnAddPause(eKResult Result, string SceneName) { }
|
|
public void OnDeletePause(eKResult Result, string SceneName) { }
|
|
public void OnSetPause(eKResult Result, string SceneName) { }
|
|
public void OnSetPauseWithIndex(eKResult Result, string SceneName) { }
|
|
public void OnDeletePauseWithIndex(eKResult Result, string SceneName) { }
|
|
public void OnQueryPauseCount(eKResult Result, string SceneName, int PauseCount) { }
|
|
public void OnQueryObjectInfos(eKResult Result, string SceneName, KAObjectInfos pObjectInfos)
|
|
{
|
|
try
|
|
{
|
|
var objects = new List<SceneObjectCatalogItem>();
|
|
if (Result == eKResult.RESULT_SUCCESS)
|
|
{
|
|
var count = pObjectInfos.GetCount();
|
|
for (var index = 0; index < count; index++)
|
|
{
|
|
var objectInfo = pObjectInfos.GetObjectInfo(index);
|
|
objects.Add(new SceneObjectCatalogItem(
|
|
objectInfo.Name ?? string.Empty,
|
|
objectInfo.ObjectType,
|
|
objectInfo.Value ?? string.Empty,
|
|
objectInfo.bVisible != 0));
|
|
}
|
|
}
|
|
|
|
_objectInfosTask.TrySetResult(new ObjectInfosProbeResult(Result, SceneName, objects, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_objectInfosTask.TrySetResult(new ObjectInfosProbeResult(
|
|
eKResult.RESULT_FAILURE,
|
|
SceneName,
|
|
Array.Empty<SceneObjectCatalogItem>(),
|
|
ex.Message));
|
|
}
|
|
}
|
|
public void OnQueryAnimationNames(eKResult Result, string SceneName, KAStrings pAnimationNames) { }
|
|
public void OnQueryAnimationCount(eKResult Result, string SceneName, int AnimationCount) { }
|
|
public void OnQueryObjectInfosByScreenPoint(eKResult Result, KAObjectInfos pObjectInfos)
|
|
{
|
|
try
|
|
{
|
|
var objects = new List<SceneObjectCatalogItem>();
|
|
if (Result == eKResult.RESULT_SUCCESS)
|
|
{
|
|
var count = pObjectInfos.GetCount();
|
|
for (var index = 0; index < count; index++)
|
|
{
|
|
var objectInfo = pObjectInfos.GetObjectInfo(index);
|
|
objects.Add(new SceneObjectCatalogItem(
|
|
objectInfo.Name ?? string.Empty,
|
|
objectInfo.ObjectType,
|
|
objectInfo.Value ?? string.Empty,
|
|
objectInfo.bVisible != 0));
|
|
}
|
|
}
|
|
|
|
_objectInfosTask.TrySetResult(new ObjectInfosProbeResult(Result, string.Empty, objects, string.Empty));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_objectInfosTask.TrySetResult(new ObjectInfosProbeResult(
|
|
eKResult.RESULT_FAILURE,
|
|
string.Empty,
|
|
Array.Empty<SceneObjectCatalogItem>(),
|
|
ex.Message));
|
|
}
|
|
}
|
|
public void OnQuerySceneEffectType(eKResult Result, string SceneName, int bInEffect, eKEffectType EffectType, int Duration) { }
|
|
public void OnQueryDuration(eKResult Result, string SceneName, string AnimationName, int Duration) { }
|
|
public void OnQueryContentsOfTextObjects(eKResult Result, string SceneName, KAStrings pTexts) { }
|
|
public void OnSetStyleColor(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
if (Result != eKResult.RESULT_ERROR_NO_VARIABLE_OBJECT)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetStyleColor result={Result} scene={SceneName} object={ObjectName}");
|
|
}
|
|
|
|
_styleColorTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetStyleTexture(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetFaceTextColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetEdgeTextColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetShadowTextColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetVisible(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
if (Result != eKResult.RESULT_ERROR_NO_VARIABLE_OBJECT)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetVisible result={Result} scene={SceneName} object={ObjectName}");
|
|
}
|
|
|
|
_visibleTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetVariableName(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetVariableName result={Result} scene={SceneName} object={ObjectName}");
|
|
_variableNameTask.TrySetResult(Result);
|
|
}
|
|
public void OnAddCloneObject(eKResult Result, string SceneName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnAddCloneObject result={Result} scene={SceneName}");
|
|
_addCloneObjectTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetTransparencyOpacity(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetTransparencyOpacity result={Result} scene={SceneName} object={ObjectName}");
|
|
_materialOpacityTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetValue(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
if (Result != eKResult.RESULT_ERROR_NO_VARIABLE_OBJECT)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetValue result={Result} scene={SceneName} object={ObjectName}");
|
|
}
|
|
|
|
_setValueTask.TrySetResult(Result);
|
|
}
|
|
public void OnAddText(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnStoreTextStyle(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetTextStyle(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnEditText(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetFont(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetTextRange(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnResetTextRange(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryObjectType(eKResult Result, string SceneName, string ObjectName, eKObjectType ObjectType)
|
|
{
|
|
Console.WriteLine($"[SDK] OnQueryObjectType result={Result} scene={SceneName} object={ObjectName} type={ObjectType}");
|
|
_objectTypeTask.TrySetResult(new ObjectTypeCallbackResult(Result, ObjectName, ObjectType, string.Empty));
|
|
}
|
|
public void OnSetChartCSVFile(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetChartCSVFile result={Result} scene={SceneName} object={ObjectName}");
|
|
_chartMutationTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetChartCellData(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetChartCellData result={Result} scene={SceneName} object={ObjectName}");
|
|
_chartMutationTask.TrySetResult(Result);
|
|
}
|
|
public void OnQueryChartDataTable(eKResult Result, string SceneName, string ObjectName, KAChartDataTable Table)
|
|
{
|
|
var rowCount = 0;
|
|
var columnCount = 0;
|
|
var cells = new List<ChartCellSnapshot>();
|
|
var detail = string.Empty;
|
|
|
|
if (Result == eKResult.RESULT_SUCCESS)
|
|
{
|
|
try
|
|
{
|
|
rowCount = Table.GetRowCount();
|
|
columnCount = Table.GetColumnCount();
|
|
|
|
for (var row = 0; row < rowCount; row++)
|
|
{
|
|
for (var column = 0; column < columnCount; column++)
|
|
{
|
|
var cell = Table.GetChartDataCell(row, column);
|
|
cells.Add(new ChartCellSnapshot(row, column, cell.Data ?? string.Empty));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
detail = ex.Message;
|
|
}
|
|
}
|
|
|
|
_chartDataTableTask.TrySetResult(new ChartDataTableProbeResult(Result, rowCount, columnCount, cells, detail));
|
|
}
|
|
public void OnQuerySize(eKResult Result, string SceneName, string ObjectName, float Width, float Height) { }
|
|
public void OnSetSize(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetSize result={Result} scene={SceneName} object={ObjectName}");
|
|
_sizeTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetCounterNumberKey(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
if (Result != eKResult.RESULT_ERROR_NO_VARIABLE_OBJECT)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetCounterNumberKey result={Result} scene={SceneName} object={ObjectName}");
|
|
}
|
|
|
|
_counterNumberKeyTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetPositionKey(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetPositionKey result={Result} scene={SceneName} object={ObjectName}");
|
|
_positionKeyTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetRotationKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetScaleKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCylinderAngleKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetSphereAngleKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCircleAngleKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCropKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCountDown(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetPosition(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
Console.WriteLine($"[SDK] OnSetPosition result={Result} scene={SceneName} object={ObjectName}");
|
|
_positionTask.TrySetResult(Result);
|
|
}
|
|
public void OnSetRotation(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetScale(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnAddPathPoint(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
_pathPointTask.TrySetResult(Result);
|
|
}
|
|
public void OnClearPathPoints(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
_pathPointTask.TrySetResult(Result);
|
|
}
|
|
public void OnAddPathShapePoint(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnClearPathShapePoints(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryScrollRemainingDistance(eKResult Result, string SceneName, string ObjectName, int ScrollRemainingDistance) { }
|
|
public void OnQueryScrollChildRemainingDistance(eKResult Result, string SceneName, string ObjectName, string ChildName, int ScrollRemainingDistance) { }
|
|
public void OnAddScrollObject(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnAdjustScrollSpeed(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetScrollSpeed(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetLoftPositionKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetChangeOut(eKResult Result, string SceneName) { }
|
|
public void OnModifyPathPoint(eKResult Result, string SceneName, string ObjectName)
|
|
{
|
|
_pathPointTask.TrySetResult(Result);
|
|
}
|
|
public void OnInitScrollObject(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCounterInfo(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCounterNumber(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCounterRange(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCounterRemainingTime(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetCounterElapsedTime(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSaveObjectImage(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetPositionOfPathAnimation(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetPositionKeyOfPathAnimation(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetStartFrame(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetObjectEffectType(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetObjectOutEffectDelay(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetColorKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetEmissiveColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetEmissiveColorKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetTransparencyOpacityKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetExposure(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetExposureKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureType(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureFile(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureOffset(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureOffsetKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureTiling(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureTilingKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureRotation(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureRotationKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureOpacity(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureOpacityKey(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryGroupType(eKResult Result, string SceneName, string ObjectName, eKGroupType GroupType) { }
|
|
public void OnQueryImageType(eKResult Result, string SceneName, string ObjectName, eKImageType ImageType) { }
|
|
public void OnSetVideoPlayInfo(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryVideoPlayInfo(eKResult Result, string SceneName, string ObjectName, ref sKVideoPlayInfo pVideoPlayInfo) { }
|
|
public void OnQueryIs3D(eKResult Result, string SceneName, string ObjectName, int b3D) { }
|
|
public void OnQueryPosition(eKResult Result, string SceneName, string ObjectName, float X, float Y, float Z)
|
|
{
|
|
Console.WriteLine($"[SDK] OnQueryPosition result={Result} scene={SceneName} object={ObjectName} pos=({X},{Y},{Z})");
|
|
_queryPositionTask.TrySetResult(new PositionCallbackResult(Result, ObjectName, X, Y, Z, string.Empty));
|
|
}
|
|
public void OnSetImageType(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMemo(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryMemo(eKResult Result, string SceneName, string ObjectName, string Memo) { }
|
|
public void OnQueryFont(eKResult Result, string SceneName, string ObjectName, ref sKFont Param) { }
|
|
public void OnSetImageOriginalSize(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnApplyChangeEffectLibrary(eKResult Result, string SceneName) { }
|
|
public void OnApplyObjectLibrary(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnApplyTextureEffectLibrary(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetTableValue(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetTableColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryTableValue(eKResult Result, string SceneName, string ObjectName, int Row, int Column, string Value) { }
|
|
public void OnQueryTableValues(eKResult Result, string SceneName, string ObjectName, KATableValues pValues) { }
|
|
public void OnSetPathShapeOutlineThickness(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnEnablePathShapeOutline(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetPlaybackCamera(eKResult Result, string SceneName) { }
|
|
public void OnSetMaterialTextureVideoPlayInfo(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnQueryMaterialTextureVideoPlayInfo(eKResult Result, string SceneName, string ObjectName, ref sKVideoPlayInfo VideoPlayInfo) { }
|
|
public void OnQueryVideoFormat(eKResult Result, ref sKVideoFormat VideoFormat) { }
|
|
public void OnQueryLiveStreamingStatus(eKResult Result, string StreamingURI, eKLiveStreamingStatus Status) { }
|
|
public void OnPreloadLiveStreaming(eKResult Result, string StreamingURI) { }
|
|
public void OnReleaseLiveStreaming(eKResult Result, string StreamingURI) { }
|
|
public void OnUpdateImageResource(eKResult Result) { }
|
|
public void OnQueryLayerCount(eKResult Result, int LayerCount) { }
|
|
public void OnSetLayerViewportRate(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnSetLayerViewportRateEx(eKResult Result, int OutputChannelIndex, int LayerNo) { }
|
|
public void OnSetFitting(eKResult Result, string SceneName) { }
|
|
public void OnSetFittingOffset(eKResult Result, string SceneName) { }
|
|
public void OnSetFittingScale(eKResult Result, string SceneName) { }
|
|
public void OnSetLightColor(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnEnableLight(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetDirectionalLight(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetPointLight(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetSpotLight(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetInfinitePointLight(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetMaterialTextureLiveStreamingURI(eKResult Result, string SceneName, string ObjectName) { }
|
|
public void OnSetBackgroundLiveStreamingURI(eKResult Result, string SceneName) { }
|
|
public void OnLoadProject(eKResult Result, string FilePath, string AliasName) { }
|
|
public void OnNewProject(eKResult Result, string AliasName) { }
|
|
public void OnUnloadAllProject(eKResult Result) { }
|
|
public void OnSaveProject(eKResult Result, string AliasName) { }
|
|
public void OnQuerySceneItemCount(eKResult Result, string AliasName, int SceneItemCount) { }
|
|
public void OnQuerySceneItemInfos(eKResult Result, string AliasName, KASceneItemInfos SceneItemInfos) { }
|
|
public void OnAddSceneItem(eKResult Result, string AliasName, int Index) { }
|
|
public void OnInsertSceneItem(eKResult Result, string AliasName) { }
|
|
public void OnDeleteSceneItem(eKResult Result, string AliasNAme) { }
|
|
public void OnQueryProjectFormat(eKResult Result, ref sKVideoFormat ProjectFormat) { }
|
|
public void OnSetTimecode(eKResult Result, string AliasName) { }
|
|
public void OnSetTimecodeInOut(eKResult Result, string AliasName) { }
|
|
public void OnSetTimecodeTrack(eKResult Result, string AliasName) { }
|
|
public void OnSetTimecodeInOutType(eKResult Result, string AliasName) { }
|
|
public void OnDeleteTimecode(eKResult Result, string AliasName) { }
|
|
public void OnQueryTimecode(eKResult Result, int TrackNo, int In, int Out, int bOnTrack) { }
|
|
public void OnUnloadProject(eKResult Result, string AliasName) { }
|
|
public void OnEnableSyncWithSceneEffect(eKResult Result, string AliasName) { }
|
|
public void OnExportProjectVideo(eKResult Result, string AliasName) { }
|
|
public void OnExportSceneImage(eKResult Result, string SceneName) { }
|
|
public void OnStartVideoCapture(eKResult Result) { }
|
|
public void OnStopVideoCapture(eKResult Result) { }
|
|
public void OnCaptureImage(eKResult Result) { }
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal struct NativeMessage
|
|
{
|
|
public IntPtr hwnd;
|
|
public uint message;
|
|
public UIntPtr wParam;
|
|
public IntPtr lParam;
|
|
public uint time;
|
|
public NativePoint pt;
|
|
public uint lPrivate;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal struct NativePoint
|
|
{
|
|
public int x;
|
|
public int y;
|
|
}
|
|
|
|
internal static class User32
|
|
{
|
|
[DllImport("user32.dll")]
|
|
internal static extern bool PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
|
|
|
|
[DllImport("user32.dll")]
|
|
internal static extern bool TranslateMessage([In] ref NativeMessage lpMsg);
|
|
|
|
[DllImport("user32.dll")]
|
|
internal static extern IntPtr DispatchMessage([In] ref NativeMessage lpMsg);
|
|
}
|