diff --git a/engine/Age.Cli/Program.cs b/engine/Age.Cli/Program.cs index 18da9da..c8de47b 100644 --- a/engine/Age.Cli/Program.cs +++ b/engine/Age.Cli/Program.cs @@ -317,6 +317,7 @@ sealed class AudioTraceHost : IHost public void ShowText(int offset, string text) { } public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int slot, int width, int height) { } public void SetTexture(long resourceId, int slot) { } 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 WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void PlayBgm(long id) { } public void PlayVoice(long id) { } } diff --git a/engine/Age.Engine.Tests/CallScriptIntegrationTests.cs b/engine/Age.Engine.Tests/CallScriptIntegrationTests.cs index 9e9ebe8..bd37d21 100644 --- a/engine/Age.Engine.Tests/CallScriptIntegrationTests.cs +++ b/engine/Age.Engine.Tests/CallScriptIntegrationTests.cs @@ -10,6 +10,7 @@ public class CallScriptIntegrationTests public void ShowText(int o, string t) { } public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int s, int w, int h) { } public void SetTexture(long r, int s) { } public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { } diff --git a/engine/Age.Engine.Tests/CallScriptTests.cs b/engine/Age.Engine.Tests/CallScriptTests.cs index 07ef8bb..7ef898a 100644 --- a/engine/Age.Engine.Tests/CallScriptTests.cs +++ b/engine/Age.Engine.Tests/CallScriptTests.cs @@ -16,6 +16,7 @@ public class CallScriptTests public void ShowText(int o, string t) { } public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int s, int w, int h) { } public void SetTexture(long r, int s) { } public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { } diff --git a/engine/Age.Engine.Tests/FrameYieldTests.cs b/engine/Age.Engine.Tests/FrameYieldTests.cs new file mode 100644 index 0000000..4622a15 --- /dev/null +++ b/engine/Age.Engine.Tests/FrameYieldTests.cs @@ -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 + } +} diff --git a/engine/Age.Engine.Tests/GameSessionTests.cs b/engine/Age.Engine.Tests/GameSessionTests.cs index a7b9d12..5cffe71 100644 --- a/engine/Age.Engine.Tests/GameSessionTests.cs +++ b/engine/Age.Engine.Tests/GameSessionTests.cs @@ -30,6 +30,7 @@ public class GameSessionTests public void ShowText(int o, string t) => Emitted.Add(o); public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int s, int w, int h) { } public void SetTexture(long r, int s) { } public void DrawTexture(int s, int sx, int sy, int w, int h, int dx, int dy) { } diff --git a/engine/Age.Engine.Tests/TestSupport.cs b/engine/Age.Engine.Tests/TestSupport.cs index 5eb70e4..f0be7ec 100644 --- a/engine/Age.Engine.Tests/TestSupport.cs +++ b/engine/Age.Engine.Tests/TestSupport.cs @@ -14,6 +14,7 @@ internal sealed class RecordingHost : IHost public void ShowText(int offset, string text) => Lines.Add((offset, text)); public void WaitForInput() => Waits++; public void Sleep(long duration) => SleptDurations.Add(duration); + public void FrameYield() { } public void CreateTexture(int slot, int w, int h) { } public void SetTexture(long resId, int slot) { } public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { } diff --git a/engine/Age.Engine.Tests/TextureGeometryTests.cs b/engine/Age.Engine.Tests/TextureGeometryTests.cs index 19dc63a..5d1773b 100644 --- a/engine/Age.Engine.Tests/TextureGeometryTests.cs +++ b/engine/Age.Engine.Tests/TextureGeometryTests.cs @@ -12,6 +12,7 @@ public class TextureGeometryTests public void ShowText(int o, string t) { } public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int slot, int w, int h) { } public void SetTexture(long resId, int slot) { } public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { } diff --git a/engine/Age.Engine.Tests/TextureOpsTests.cs b/engine/Age.Engine.Tests/TextureOpsTests.cs index ed61920..96e16e6 100644 --- a/engine/Age.Engine.Tests/TextureOpsTests.cs +++ b/engine/Age.Engine.Tests/TextureOpsTests.cs @@ -14,6 +14,7 @@ public class TextureOpsTests public void ShowText(int o, string t) { } public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int slot, int w, int h) => Creates++; 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)); diff --git a/engine/Age.Engine/Hosting/CaptureHost.cs b/engine/Age.Engine/Hosting/CaptureHost.cs index 42a5c48..da651fa 100644 --- a/engine/Age.Engine/Hosting/CaptureHost.cs +++ b/engine/Age.Engine/Hosting/CaptureHost.cs @@ -5,6 +5,7 @@ public sealed class CaptureHost : IHost public void ShowText(int offset, string text) => Emitted.Add((offset, text)); public void WaitForInput() { } public void Sleep(long duration) { } + public void FrameYield() { } public void CreateTexture(int slot, int width, int height) { } public void SetTexture(long resourceId, int slot) { } public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { } diff --git a/engine/Age.Engine/Hosting/IHost.cs b/engine/Age.Engine/Hosting/IHost.cs index 55022b1..d50e128 100644 --- a/engine/Age.Engine/Hosting/IHost.cs +++ b/engine/Age.Engine/Hosting/IHost.cs @@ -4,6 +4,7 @@ public interface IHost void ShowText(int offset, string text); void WaitForInput(); void Sleep(long duration); + void FrameYield(); void CreateTexture(int slot, int width, int height); void SetTexture(long resourceId, int slot); void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY); diff --git a/engine/Age.Engine/Vm/VirtualMachine.cs b/engine/Age.Engine/Vm/VirtualMachine.cs index fd213a3..cf85f3d 100644 --- a/engine/Age.Engine/Vm/VirtualMachine.cs +++ b/engine/Age.Engine/Vm/VirtualMachine.cs @@ -122,6 +122,7 @@ public sealed class VirtualMachine Steps++; if (_sink.TracingSteps) _sink.Emit(TraceEvent.Step(pc, frame.Script.Instructions[pc], _depth)); int next = Step(frame.Script.Instructions[pc], pc); + _host.FrameYield(); if (next == FRAME_RETURN) { outcome = FrameOutcome.Returned; break; } if (next == HALT) { outcome = FrameOutcome.Halted; break; } pc = next;