Overview of SadConsole.Host.MonoGameWPF
master..\\\SadConsole.Host.MonoGame\\\ directory, specifically applying filters compatible with the WPF (Windows Presentation Foundation) environment.repository·master·Indexed 23 days ago
https://github.com/thraka/sadconsoleA cross-platform .NET engine for building ASCII and terminal-style games using a tile-based approach. It features multi-console support, a GUI system with interactive controls, an entity system, and support for .NET 8, 9, and 10. The engine requires a host library for rendering, with available options including SadConsole.Host.MonoGame, SadConsole.Host.SFML, and SadConsole.Host.MonoGameWPF. Additional functionality is provided via SadConsole.Extended and a suite of Roslyn analyzers in SadConsole.Analyzers to detect common development anti-patterns.
..\\\SadConsole.Host.MonoGame\\\ directory, specifically applying filters compatible with the WPF (Windows Presentation Foundation) environment.SadConsole is a C#-based .NET cross-platform engine designed for creating terminal, ASCII, and console-style games. While it functions as a giant tile-based game engine, its object model is designed to feel conceptually similar to a traditional console application.
Key capabilities include:
The SadConsole test suite is currently thin, primarily covering CellSurface manipulation, ScreenObject hierarchy, and Extended.Table components. Most high-level features—including UI controls, the effects system, string parsing, input handling, and ANSI processing—have little to no test coverage.
If you are contributing to the library or building complex applications on top of it, be aware that regressions in the following areas are more likely to occur due to lack of automated testing:
ColoredString and its various ParseCommand* types (e.g., ParseCommandBlink, ParseCommandGradient).TextBox, ListBox, ComboBox, Button, ScrollBar, etc.Blink, Fade, and Recolor managed by EffectsManager.The IComponent system allows you to attach custom logic to any IScreenObject without subclassing it. Components can participate in various lifecycle events by declaring their interest in:
IsUpdate: Logic to run every frame.IsRender: Logic to run during the render phase.IsMouse: Logic to handle mouse input.IsKeyboard: Logic to handle keyboard input.To use a component, you attach it to an IScreenObject (which acts as the IComponentHost).
The rendering process follows a deferred, layered approach to minimize GPU state switches and optimize performance:
GameHost.FrameUpdate triggers IScreenObject.Update, which recursively updates children and attached IComponents.GameHost.FrameRender triggers IScreenObject.Render.IScreenSurface is dirty, its IRenderer performs a Refresh(). This involves iterating through IRenderSteps:step.Refresh(...): Re-rasterizes cells into a backing texture.step.Composing(...): Composites layers onto the IRenderer.Output.Render() method iterates through IRenderSteps to call step.Render(...), which enqueues IDrawCall objects into a queue.SpriteBatch.Draw in MonoGame) to draw the final pixels to the GPU.The ScreenSurface is a core component of the SadConsole scene graph. It inherits from ScreenObject, which provides the base scene-graph functionality (children, parent, position, visibility, components, and input routing).
Common implementations include:
Console: A standard ScreenSurface with a Cursor component added.LayeredScreenSurface: Adds a LayeredSurface component and ILayeredData support.UI.WindowConsole: A specialized surface for UI windows, inheriting from UI.ControlsConsole which adds a ControlHost component.object
└─ ScreenObject (IScreenObject)
└─ ScreenSurface (IScreenSurfaceEditable, ISurfaceSettable, ICellSurfaceResize, IDisposable)
├─ Console (adds Cursor component)
├─ LayeredScreenSurface (adds LayeredSurface component, ILayeredData)
└─ UI.ControlsConsole (adds ControlHost component)
└─ UI.WindowConsoleWhen serializing a ScreenSurface (e.g., for saving game state), SadConsole does not embed the actual font texture data to avoid massive save files. Instead, it uses a FontJsonConverter that only stores the font's name.
Serialization Workflow:
IFont is serialized as a FontSerialized object containing only the Name property.GameHost.Instance.Fonts.GameHost.Instance.DefaultFont.Requirement: You must ensure all fonts referenced by your surfaces are registered in GameHost.Fonts before you attempt to deserialize the game state.
When a control has multiple active states (e.g., it is both Focused and MouseOver), the visual appearance is determined by a deterministic priority order defined in ThemeStates.GetStateAppearance. The priority is as follows (from highest to lowest):
This ensures that the UI appearance remains predictable even when multiple state flags are active simultaneously.
A CellSurface supports a scrollable viewport via a BoundedRectangle called _viewArea. This allows you to have a large buffer of data while only displaying a specific sub-region.
Key viewport properties:
Area: The full bounds of the buffer (0, 0, totalWidth, totalHeight).View: The visible rectangle (a sub-region of Area).ViewPosition: The anchor point of the viewport within the buffer.ViewWidth / ViewHeight: The dimensions of the visible area.IsScrollable: true if the View dimensions differ from the Area dimensions.To implement scrolling, you modify the ViewPosition.
SadConsole uses a strict separation between the object model and the rendering implementation. This allows the same game logic to run on different graphics frameworks.
SadConsole): Defines the object model, including surfaces, cells, fonts, input handling, the scene graph, entities, and the GUI system. It contains zero rendering code and only interacts with abstract interfaces like IRenderer, ITexture, and IFont.SadConsole.Host.*): These are the actual rendering engines (e.g., SadConsole.Host.MonoGame, SadConsole.Host.FNA, SadConsole.Host.SFML). A consumer app should reference only one host library, which then pulls in the core library as a dependency.When building an app, you choose a host based on your preferred rendering framework (e.g., use SadConsole.Host.MonoGame if you are using MonoGame).
Dirty tracking occurs at two granularities to optimize rendering and effects:
CellSurface.IsDirty): A boolean flag that signals the renderer to re-bake its backing texture. It is set to true by mutating operations and raises the IsDirtyChanged event. The renderer resets this to false after a successful Refresh.ColoredGlyphBase.IsDirty): A flag set when an individual cell's property changes. This is used by the EffectsManager to determine which cells need processing. It raises the IsDirtySet event.ScreenSurface objects subscribe to Surface.IsDirtyChanged to react to changes in their underlying data.