f6d9ea896f921de6244f214a2bd2341e2cd4c323
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f6d9ea896f |
Close M1: real triangle, engine.input, screenshot-to-file capture
All three plugins M1 called for now exist over Silk.NET, and the milestone's actual claim is proven against a live GL context, not just argued: edit a plugin's code, rebuild just it, reload it while a real window stays open, see the change with no app restart. Verified directly this time — two PNGs of the same running window, before and after a live reload (orange triangle -> green, same process, same window, same GL context throughout) — not by analogy to the earlier clear-color version. engine.render, upgraded from clear-color to real geometry: - Vertex/fragment shaders compiled and linked at Configure() time, with real error checking (GetShader/GetProgram *Status + InfoLog on failure) rather than trusting hand-typed GLSL to just work. - VAO/VBO for a hardcoded triangle; Shutdown() deletes all three GL objects rather than leaking them across reloads. - unsafe confined to Configure() (VertexAttribPointer takes a raw offset pointer) via a narrow, documented override of Directory.Build.props' default — native graphics interop, not the kernel data structures docs/kernel-contract.md §7 was written against. engine.input: publishes IEngineInput (keyboard state) via Silk.NET.Input. Reuses Silk.NET's own Key enum rather than inventing one, same call as IEngineWindow.Native. Loads and constructs cleanly against a real window; nothing reacts to it yet since there's no gameplay code to. IScreenCapture (new, engine.render): reads the frame back via ReadPixels and writes a PNG. No SixLabors.ImageSharp — checked its license first and it isn't MIT/Apache (revenue-gated), which would have been a real surprise for downstream users of an MIT engine. PngWriter is a from-scratch encoder instead: ZLibStream (BCL, .NET 6+) for the one genuinely hard part, a correctly zlib-wrapped DEFLATE stream; chunk framing and CRC32 are small enough to get right and to verify by actually decoding files this wrote (done repeatedly, by hand, across this session). Engine.Host: "screenshot <path>" joins "r <plugin-id>" as a live stdin command, plus a non-interactive --screenshot/--screenshot-after- frames pair that captures once and exits — for scripts and agents that can't easily hold a pipe open into a long-running process. Real bug found and fixed in PluginHost, not specific to any one environment: loading a Contracts assembly into the Default ALC never set up resolution for ITS OWN dependencies. engine.windowing's and engine.render's Contracts both need Silk.NET packages and loaded fine anyway, by accident — Engine.Host references those two Contracts projects directly (to drive the windowed loop and screenshot capture), so their dependencies were already sitting in Engine.Host's own output directory. engine.input's Contracts has no such lucky coincidence and failed with a real FileNotFoundException. Fixed by hooking AssemblyLoadContext.Default.Resolving with an AssemblyDependencyResolver per loaded Contracts path — mirroring what PluginLoadContext already does for collectible ALCs, applied to the one path that never had it. Hooked once per process via a static list/flag, not per PluginHost instance, specifically to avoid a PluginHost instance becoming unreclaimable through its own event subscription. Not covered by automated tests, deliberately, same reasoning as the windowing/render pass: opening a real window and reading back a real framebuffer both need a real display. Verified by hand instead, documented above and in commit history rather than asserted. README status: M1 done, not "in progress." Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N1qPfzq8TDCUMFMV3UwV5N |
||
|
|
c5d3807a0f |
M1 (in progress): engine.windowing + engine.render, hot-reload proven live
The first plugins with a real external dependency (Silk.NET) and the first that need a display. Both built, both verified by hand against a real window and a live GL context — not just "compiles." engine.windowing: - IEngineWindow, not IWindow — Silk.NET's own windowing type already owns that name; same lesson as the kernel's World -> GameWorld rename, applied proactively this time instead of hitting the build error first. docs/kernel-contract.md's §3 illustrative example updated to match. - Exposes the real Silk.NET IWindow directly (IEngineWindow.Native) rather than re-wrapping it — GL context creation and event pumping both need it, and hiding it buys nothing yet. engine.render: - Minimal: glClear + SwapBuffers against a hardcoded color, no mesh. Enough to prove M1's actual claim, which has nothing to do with triangles specifically: edit a plugin, rebuild just it, reload it while a real window stays open, see the change with no app restart. - No Contracts assembly — PluginManifest.Contracts is now nullable rather than forcing an empty assembly into existence just to satisfy the schema; PluginHost.Load skips the Default-ALC step when absent. Engine.Host: - --windowed alongside --headless: pumps window events plus Stage.Update/Stage.Render each frame instead of a bounded --frames loop. References Engine.Windowing.Contracts directly (never the implementation) to know how to drive that loop — same "Contracts are safe to share" pattern already proven for Sandbox.Echo.Contracts. - New: typing "r <plugin-id>" + Enter reloads that plugin live. Not a file watcher (still not built), but real Unload+Load through the same PluginHost path, against a running window — this is what actually exercised the hot-reload claim below. - IServiceRegistry gained TryRequire<T> so Engine.Host can ask "is a window available" without treating its absence as an error; a plugin's own Configure()/Shutdown() should keep using Require(). Verified end to end by hand: opened the window, watched it render its hardcoded color, edited RenderPlugin.cs's ClearColor, rebuilt only that project, typed "r engine.render" into the running process, and watched the color change with the same window and GL context still alive. Also found and documented a real platform gotcha along the way: on Wayland (unlike X11), a window with no committed buffer isn't shown at all, not even as a black rectangle — engine.windowing alone produces an invisible window; engine.render's first Clear+SwapBuffers is what actually makes it appear. Noted directly on RenderPlugin. Not covered by automated tests, deliberately: opening a real window needs a real display, which isn't safe to assume of every environment this runs in. ServiceRegistry.TryRequire<T> and the null-Contracts path in PluginHost are unit-tested; the window/render/reload flow is described here and was checked by hand instead. README status updated: M1 in progress, not done — engine.input and an actual drawn triangle (vs. a clear color) are still open. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N1qPfzq8TDCUMFMV3UwV5N |