SadConsole Documentation

repository·master·Indexed 23 days ago

https://github.com/thraka/sadconsole

A 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.

Tokens
25.6K
Snippets
30
Records
110
Agent score
80%

What's inside SadConsole

  1. Overview of SadConsole

    master

    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:

    • Multi-Console Support: Display any number of consoles of varying sizes.
    • Advanced Typography: Uses graphical tile-based images to build ASCII fonts, supporting more than 256 characters. Fonts are essentially sprite sheet tilesets mapped to ASCII codes.
    • GUI System: Includes a full suite of interactive controls like list boxes, buttons, and text fields.
    • Rich Text: Features a string encoding system for applying colors and effects during printing.
    • Entity System: Supports drawing thousands of movable objects (entities) on the screen.
    • Input Support: Built-in support for keyboard and mouse interaction.
    • Asset Importers: Native support for DOS ANSI files, TheDraw text fonts, RexPaint, and Playscii.
  2. Overview of SadConsole.Extended

    master
    SadConsole.Extended is an extension package for the SadConsole engine. It provides additional UI controls, windows, and various components designed to work with the core SadConsole engine. While SadConsole itself is a tile-based engine for creating ASCII-styled games, this package extends its capabilities by providing higher-level UI abstractions.
  3. Understand SadConsole test coverage and risk areas

    master

    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:

    • String Parsing: ColoredString and its various ParseCommand* types (e.g., ParseCommandBlink, ParseCommandGradient).
    • UI Controls: TextBox, ListBox, ComboBox, Button, ScrollBar, etc.
    • Effects System: Animated features like Blink, Fade, and Recolor managed by EffectsManager.
    • Input: Keyboard and mouse state tracking.
    • Cursor Logic: Text rendering behaviors like auto-wrap, auto-scroll, and backspace.
    • Instructions: Scripted sequences and coroutine-like execution.
  4. Use IComponent to add behavior to screen objects

    master

    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).

  5. How the SadConsole rendering pipeline works

    master

    The rendering process follows a deferred, layered approach to minimize GPU state switches and optimize performance:

    1. Update Phase: GameHost.FrameUpdate triggers IScreenObject.Update, which recursively updates children and attached IComponents.
    2. Render Phase: GameHost.FrameRender triggers IScreenObject.Render.
    3. Surface Refresh: If an 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.
    4. Draw Call Enqueueing: The renderer's Render() method iterates through IRenderSteps to call step.Render(...), which enqueues IDrawCall objects into a queue.
    5. Host Flush: The host library flushes the accumulated draw-call list to the underlying graphics API (e.g., SpriteBatch.Draw in MonoGame) to draw the final pixels to the GPU.
  6. Understand the ScreenSurface inheritance hierarchy

    master

    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.WindowConsole
  7. Serialize and deserialize fonts in game state

    master

    When 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:

    1. Write: The IFont is serialized as a FontSerialized object containing only the Name property.
    2. Read: The system deserializes the name and looks it up in GameHost.Instance.Fonts.
    3. Fallback: If the named font is not found in the registry, it falls back to 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.

  8. Understand Control State Appearance Priority

    master

    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):

    1. Disabled
    2. MouseDown
    3. MouseOver
    4. Focused
    5. Selected
    6. Normal

    This ensures that the UI appearance remains predictable even when multiple state flags are active simultaneously.

  9. How the CellSurface viewport system works

    master

    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.

  10. Understand the SadConsole Core/Host separation

    master

    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.

    • Core Library (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.
    • Host Libraries (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).

  11. How dirty tracking works in SadConsole

    master

    Dirty tracking occurs at two granularities to optimize rendering and effects:

    1. Surface-level (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.
    2. Cell-level (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.