FS.GG.Game.Core
0.13.0
Prefix Reserved
dotnet add package FS.GG.Game.Core --version 0.13.0
NuGet\Install-Package FS.GG.Game.Core -Version 0.13.0
<PackageReference Include="FS.GG.Game.Core" Version="0.13.0" />
<PackageVersion Include="FS.GG.Game.Core" Version="0.13.0" />
<PackageReference Include="FS.GG.Game.Core" />
paket add FS.GG.Game.Core --version 0.13.0
#r "nuget: FS.GG.Game.Core, 0.13.0"
#:package FS.GG.Game.Core@0.13.0
#addin nuget:?package=FS.GG.Game.Core&version=0.13.0
#tool nuget:?package=FS.GG.Game.Core&version=0.13.0
FS.GG.Game.Core
BCL-only deterministic simulation core for FS.GG.Game — the platform's bottom layer.
Depends on nothing but FSharp.Core and reaches up to no other FS-GG package.
The sim vocabulary
The shared types — Point, Rect, Circle, ConvexPolygon, and the detection values Contact (a single-axis penetration manifold), Manifold (its multi-point form) and RayHit (a segment-cast result) — live directly in the FS.GG.Game.Core namespace, so open FS.GG.Game.Core is all a caller needs. The tile index Cell is namespace-level too. Everything below is a [<RequireQualifiedAccess>] module, called as Grids.cellAt, Rng.nextInt, and so on.
Rng— SplitMix64 seeded RNG (ofSeed/nextInt/nextFloat/nextBool/split), byte-identical across runs.FixedStep— fixed-timestep accumulator drain (drain/drainWith). No wall-clock read, so a scripted frame time replays exactly.Loop— the fixed-step double-buffered loop built onFixedStep.drain(advance/alpha): the world as of the last completed step (Current), the one before it (Previous), and the carried sub-step time (Accumulator). Renderers interpolatePrevious → Currentbyalpha, so motion is smooth at any frame rate while the sim only ever advances by whole fixed steps. The default for any continuously-moving simulation.InputCommand— the abstract, device-free vocabulary of input intents (Command.MoveNorth/…/Fire/Pause) as pure data. The policy half of the input split:Game.Coreowns which commands exist; the render/input layer owns how a device makes one and never learns a game action.
Collision — detection, then response
Geometry— the detection surface: overlap and containment for AABB, circle, and convex polygon (intersects/contains/aabbContact/circleContact/polygonContact/obbPolygon), swept tests (sweptIntersects), and segment casts (segmentAabbHit/segmentCircleHit/segmentPolygonHit/…). It returns manifests as values and never resolves them.Resolution— the response layer that consumes a detectionContactand produces transforms (pushOut/slide/push;knockbackis a deprecated shim overpush). Deliberately separate from detection; it never re-detects.SpatialGrid— uniform spatial partitioning for the broad phase (build/query/queryRadius).Physics— an opt-in mini rigid-body engine: a world of bodies, a broad phase, a narrow phase, and a semi-implicit Euler step with a warm-started sequential-impulse contact solver over bodies that sleep once they settle. Mass is derived from a shape's area, not given. ArcadeResolutionstays the first-class default; neither module knows the other.
The grid
Pathfinding— grid A*/BFS over walkable cells (astar/bfs), the turn-based-tactics move range (reachable/pathTo), and the many-to-one AI substratedistanceField/flowField/reachableWithin. Pick by the question:astarminimises steps and takes nocost, so it is the wrong tool for a unit spending a movement budget over non-uniform terrain —reachablecosts the highlight and the path in one search, andpathTowalks it.reachableWithinis that search with the predecessors dropped: the costed set, for scoring cells or a threat overlay, not for pathing to one.Grids— the parts of a square grid:Edge,Vertex,GridSpec, the six adjacency conversions, and the pixel↔cell map (cellRect/cellCenter/edgeSegment/cellAt). Names the boundary between two tiles, which is where a wall lives.
Sight
Los— point-to-point grid line of sight over a caller-supplied opacity predicate (line/supercover/trace/lineOfSight).Fov— grid field of view by symmetric shadowcasting (fov). Opacity is not walkability: this module consults opacity only.Visibility— the continuous-space sibling: exact point-to-point sight against arbitrary occluder segments, and the full angular-sweep visibility polygon (raySegment/isVisible/polygon). It can answer occlusion between two moving bodies, which a tile walk cannot.
Pathfinding, Los, and Fov all take terrain as a pure Cell -> bool predicate — the framework holds no map, so one terrain plugs into all three.
Combat and decision
Ballistics— projectile weapons over continuous space: a swept advance that cannot tunnel (a fast round is a segment, never a point), a lead / intercept solve, and a splash query with a caller-chosen falloff. Lifetimes are counted in whole ticks, not float seconds, so a replay cannot drift.Effects— the mitigation layer: what one incoming hit becomes at the target. It separates the damageSource(aDeclaredattack — the only thing cover and armor reduce — vsCollision/Environmental/Periodic) from the damage kind, which stays generic in'K(Game.Corenever learns what Frost is).Ai— the decision layer's vocabulary: a comparableAgentIdthat fixes iteration order (never hash order, which would diverge a replay), and the fog-of-warTeamView— an abstract value of what a team knows, whose sightings decay from spotted into ghosts. Its LOS is a caller-supplied oracle, so perception policy stays with the game.
Where it came from
Three provenances:
- Extracted from
FS.GG.UI.Canvas/FS.GG.UI.Sceneand reimplemented BCL-only, per ADR-0022 — the shared types,Geometry,Rng,FixedStep,Pathfinding,SpatialGrid. - Promoted from the frozen starter fragments in
FS.GG.Rendering(template/fragments/*), which every game that wanted them previously had to copy and diverge from —Los,Visibility,Grids. - Authored here through the SDD lifecycle, because the org had nothing to promote —
Fov,Resolution,Loop,InputCommand,Ballistics,Effects,Ai, andPhysics.
Guarantees
Headlessly testable — zero Skia, zero Scene. Purity, totality (degenerate and non-finite input degrades to a documented value rather than throwing), and determinism (integer logic / float presentation) are the contract each module's .fsi states and its tests hold it to — so identical input replays byte-identically across runs, and a module is safe to call from a replayed simulation step. Cross-platform byte-identity is unconditional for the integer / grid layer; the float-heavy modules scope it (Visibility to |coord| <= 1e6) or defer full lockstep to a later fixed-point ADR (Physics.checksum), so trust the per-module .fsi, not one blanket claim.
Fable compatibility
The NuGet package carries a bounded Fable source view containing the canonical
Primitives, Pathfinding, Edges, and Los source files used by the .NET
assembly; it does not contain copied algorithms. The package's
fable-compatibility/ directory records the versioned profile, authored input
vectors, canonical binary oracle, fixture schema, and pinned toolchain.
Cell ordering, Edges.edgeBetween, Los.lineOfSightBy, and
Pathfinding.astar are LockstepExact under profile
fs-gg-game-core-fable-lockstep-v1. The packed .NET assembly and
package-derived Fable source must emit byte-identical records for the shared
boundary corpus. Floating value types are Portable, not exact; implementation
surfaces excluded from the source view are DotNetOnly. Every other operation
remains unclassified even when its source file is present.
To project sim state onto drawables, add FS.GG.Game.Render.
House style: .fsi is the sole public surface; net10.0; -preview channel.
See FS-GG/FS.GG.Game and ADR-0022.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FSharp.Core (>= 10.1.302)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on FS.GG.Game.Core:
| Package | Downloads |
|---|---|
|
FS.GG.Game.Render
Pure Scene adapter and input policy for FS.GG.Game — projects FS.GG.Game.Core simulation primitives (Point/Rect/Cell and pathfinding routes) onto FS.GG.UI.Scene drawables at the render edge, and ships the default command→key keymap binding the Game.Core command vocabulary onto FS.GG.UI.KeyboardInput's keymap mechanism. Reaches UP to FS.GG.UI.*; no Skia, deterministic. Per ADR-0022 §2. |
|
|
FS.GG.Game.Harness
Deterministic, headless gameplay test harness on FS.GG.Game.Core. Drives a game's world through the standard Command input frontier — scripted raw-key→keymap→Command, an in-process Bot policy, and a multi-seed bot-vs-bot matrix — folds whole fixed steps, and fingerprints the world trace as a value so a replay is a comparison, not a tolerance check. A typed synthetic-state escape hatch keeps its own evidence self-identifying. Depends on nothing but FS.GG.Game.Core and the BCL. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.13.0 | 7 | 7/28/2026 |
| 0.12.0 | 655 | 7/26/2026 |
| 0.11.0 | 135 | 7/26/2026 |
| 0.10.1 | 276 | 7/26/2026 |
| 0.10.0 | 88 | 7/25/2026 |
| 0.9.1 | 96 | 7/25/2026 |
| 0.9.0 | 459 | 7/22/2026 |
| 0.8.0 | 257 | 7/21/2026 |
| 0.7.1 | 1,165 | 7/19/2026 |
| 0.7.0 | 120 | 7/19/2026 |
| 0.6.0 | 115 | 7/19/2026 |
| 0.5.1 | 156 | 7/18/2026 |
| 0.5.0 | 736 | 7/16/2026 |
| 0.4.0 | 1,546 | 7/11/2026 |
| 0.3.0 | 2,233 | 7/10/2026 |
| 0.2.0 | 199 | 7/9/2026 |
| 0.1.0-preview.1 | 366 | 7/6/2026 |