feat: add IHost.FrameYield per-opcode hook (no-op headless, parity held)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -317,6 +317,7 @@ sealed class AudioTraceHost : IHost
|
|||||||
public void ShowText(int offset, string text) { }
|
public void ShowText(int offset, string text) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int slot, int width, int height) { }
|
public void CreateTexture(int slot, int width, int height) { }
|
||||||
public void SetTexture(long resourceId, int slot) { }
|
public void SetTexture(long resourceId, int slot) { }
|
||||||
public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { }
|
public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { }
|
||||||
@@ -366,6 +367,7 @@ sealed class GfxTraceHost : IHost
|
|||||||
public void ShowText(int offset, string text) { }
|
public void ShowText(int offset, string text) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void PlayBgm(long id) { }
|
public void PlayBgm(long id) { }
|
||||||
public void PlayVoice(long id) { }
|
public void PlayVoice(long id) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ public class CallScriptIntegrationTests
|
|||||||
public void ShowText(int o, string t) { }
|
public void ShowText(int o, string t) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int s, int w, int h) { }
|
public void CreateTexture(int s, int w, int h) { }
|
||||||
public void SetTexture(long r, int s) { }
|
public void SetTexture(long r, int s) { }
|
||||||
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class CallScriptTests
|
|||||||
public void ShowText(int o, string t) { }
|
public void ShowText(int o, string t) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int s, int w, int h) { }
|
public void CreateTexture(int s, int w, int h) { }
|
||||||
public void SetTexture(long r, int s) { }
|
public void SetTexture(long r, int s) { }
|
||||||
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
|||||||
35
engine/Age.Engine.Tests/FrameYieldTests.cs
Normal file
35
engine/Age.Engine.Tests/FrameYieldTests.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Age.Engine.Hosting;
|
||||||
|
using Age.Engine.Model;
|
||||||
|
using Age.Engine.Sys4;
|
||||||
|
using Age.Engine.Vm;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class FrameYieldTests
|
||||||
|
{
|
||||||
|
private sealed class CountingHost : IHost
|
||||||
|
{
|
||||||
|
public long Yields;
|
||||||
|
public void FrameYield() => Yields++;
|
||||||
|
public void ShowText(int offset, string text) { }
|
||||||
|
public void WaitForInput() { }
|
||||||
|
public void Sleep(long duration) { }
|
||||||
|
public void CreateTexture(int slot, int width, int height) { }
|
||||||
|
public void SetTexture(long resourceId, int slot) { }
|
||||||
|
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
public (int Width, int Height) GetTextureSize(int slot) => (0, 0);
|
||||||
|
public void PlayBgm(long id) { }
|
||||||
|
public void PlayVoice(long id) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FrameYield_CalledOncePerStep()
|
||||||
|
{
|
||||||
|
var table = OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||||
|
var script = Sys4Loader.Load(Paths.Scripts()["INITCONFIG.BIN"], table);
|
||||||
|
var host = new CountingHost();
|
||||||
|
var vm = new VirtualMachine(script, table, host);
|
||||||
|
vm.Run();
|
||||||
|
Assert.True(vm.Steps > 0);
|
||||||
|
Assert.Equal(vm.Steps, host.Yields); // exactly one FrameYield per executed opcode
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ public class GameSessionTests
|
|||||||
public void ShowText(int o, string t) => Emitted.Add(o);
|
public void ShowText(int o, string t) => Emitted.Add(o);
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int s, int w, int h) { }
|
public void CreateTexture(int s, int w, int h) { }
|
||||||
public void SetTexture(long r, int s) { }
|
public void SetTexture(long r, int s) { }
|
||||||
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ internal sealed class RecordingHost : IHost
|
|||||||
public void ShowText(int offset, string text) => Lines.Add((offset, text));
|
public void ShowText(int offset, string text) => Lines.Add((offset, text));
|
||||||
public void WaitForInput() => Waits++;
|
public void WaitForInput() => Waits++;
|
||||||
public void Sleep(long duration) => SleptDurations.Add(duration);
|
public void Sleep(long duration) => SleptDurations.Add(duration);
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int slot, int w, int h) { }
|
public void CreateTexture(int slot, int w, int h) { }
|
||||||
public void SetTexture(long resId, int slot) { }
|
public void SetTexture(long resId, int slot) { }
|
||||||
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class TextureGeometryTests
|
|||||||
public void ShowText(int o, string t) { }
|
public void ShowText(int o, string t) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int slot, int w, int h) { }
|
public void CreateTexture(int slot, int w, int h) { }
|
||||||
public void SetTexture(long resId, int slot) { }
|
public void SetTexture(long resId, int slot) { }
|
||||||
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class TextureOpsTests
|
|||||||
public void ShowText(int o, string t) { }
|
public void ShowText(int o, string t) { }
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int slot, int w, int h) => Creates++;
|
public void CreateTexture(int slot, int w, int h) => Creates++;
|
||||||
public void SetTexture(long resId, int slot) => Sets.Add((resId, slot));
|
public void SetTexture(long resId, int slot) => Sets.Add((resId, slot));
|
||||||
public void DrawTexture(int slot, int srcX, int srcY, int w, int h, int dstX, int dstY) => Draws.Add((slot, w, h));
|
public void DrawTexture(int slot, int srcX, int srcY, int w, int h, int dstX, int dstY) => Draws.Add((slot, w, h));
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ public sealed class CaptureHost : IHost
|
|||||||
public void ShowText(int offset, string text) => Emitted.Add((offset, text));
|
public void ShowText(int offset, string text) => Emitted.Add((offset, text));
|
||||||
public void WaitForInput() { }
|
public void WaitForInput() { }
|
||||||
public void Sleep(long duration) { }
|
public void Sleep(long duration) { }
|
||||||
|
public void FrameYield() { }
|
||||||
public void CreateTexture(int slot, int width, int height) { }
|
public void CreateTexture(int slot, int width, int height) { }
|
||||||
public void SetTexture(long resourceId, int slot) { }
|
public void SetTexture(long resourceId, int slot) { }
|
||||||
public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { }
|
public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ public interface IHost
|
|||||||
void ShowText(int offset, string text);
|
void ShowText(int offset, string text);
|
||||||
void WaitForInput();
|
void WaitForInput();
|
||||||
void Sleep(long duration);
|
void Sleep(long duration);
|
||||||
|
void FrameYield();
|
||||||
void CreateTexture(int slot, int width, int height);
|
void CreateTexture(int slot, int width, int height);
|
||||||
void SetTexture(long resourceId, int slot);
|
void SetTexture(long resourceId, int slot);
|
||||||
void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY);
|
void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY);
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ public sealed class VirtualMachine
|
|||||||
Steps++;
|
Steps++;
|
||||||
if (_sink.TracingSteps) _sink.Emit(TraceEvent.Step(pc, frame.Script.Instructions[pc], _depth));
|
if (_sink.TracingSteps) _sink.Emit(TraceEvent.Step(pc, frame.Script.Instructions[pc], _depth));
|
||||||
int next = Step(frame.Script.Instructions[pc], pc);
|
int next = Step(frame.Script.Instructions[pc], pc);
|
||||||
|
_host.FrameYield();
|
||||||
if (next == FRAME_RETURN) { outcome = FrameOutcome.Returned; break; }
|
if (next == FRAME_RETURN) { outcome = FrameOutcome.Returned; break; }
|
||||||
if (next == HALT) { outcome = FrameOutcome.Halted; break; }
|
if (next == HALT) { outcome = FrameOutcome.Halted; break; }
|
||||||
pc = next;
|
pc = next;
|
||||||
|
|||||||
Reference in New Issue
Block a user