Zaldaryon.Pharos.XUnit 0.4.0

dotnet add package Zaldaryon.Pharos.XUnit --version 0.4.0
                    
NuGet\Install-Package Zaldaryon.Pharos.XUnit -Version 0.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zaldaryon.Pharos.XUnit" Version="0.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zaldaryon.Pharos.XUnit" Version="0.4.0" />
                    
Directory.Packages.props
<PackageReference Include="Zaldaryon.Pharos.XUnit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zaldaryon.Pharos.XUnit --version 0.4.0
                    
#r "nuget: Zaldaryon.Pharos.XUnit, 0.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zaldaryon.Pharos.XUnit@0.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zaldaryon.Pharos.XUnit&version=0.4.0
                    
Install as a Cake Addin
#tool nuget:?package=Zaldaryon.Pharos.XUnit&version=0.4.0
                    
Install as a Cake Tool

<p align="center"> <img src="docs/pharos-logo.svg" alt="Pharos logo" width="120" height="120" /> </p>

Pharos

In-process headless test harness for Vintage Story client and server systems. Pharos boots a real Vintage Story client or server inside your test process, drives it frame by frame or tick by tick, and exposes rendering and world-state inspection APIs to xUnit test code.

What It Does

Pharos runs Vintage Story inside your test process. The client loads chunks, meshes geometry, and issues OpenGL draw calls exactly like the normal client, but with no visible window and no audio. The server runs a full simulation loop with a real player registry and savegame stack, but in an isolated temporary sandbox. Your test code controls the frame and tick loops, positions the camera, inspects rendering state, places blocks, and asserts on results.

Use cases:

  • Rendering regression tests for client-side mods
  • Server-side integration tests without a running game instance
  • Performance benchmarks that measure actual draw calls and allocations
  • Visual diff tests comparing framebuffer output across versions
  • Automated smoke tests for mod compatibility
  • Lockstep client-server end-to-end scenario testing

Requirements

  • Vintage Story 1.22.x (1.22.7 recommended)
  • .NET 10 SDK
  • OpenGL 4.3+ for full inspection features (3.3 for basic headless)
  • Windows or Linux (macOS not supported)

See the compatibility matrix for version details.

Installation

Client scenario testing

Add the Pharos XUnit metapackage to your test project:

dotnet add package Zaldaryon.Pharos.XUnit

This brings in the core library, xUnit integration, and xUnit itself.

Server scenario testing

The server APIs are part of the same package. No extra package is needed.

Migrating from Pixnop.Atlas

If you have existing Atlas test suites, install the compatibility shim for zero-code-change migration:

dotnet add package Zaldaryon.Pharos.AtlasCompat

Or use the CLI migration tool:

pharos migrate-atlas ./your-test-project

See Migrating from Atlas for the full guide.

Set the VINTAGE_STORY environment variable to your game installation:

# Windows (PowerShell)
$env:VINTAGE_STORY = "C:\Program Files\Vintage Story"

# Linux
export VINTAGE_STORY=~/.local/share/vintagestory

Quick Start: Client Scenarios

Create a test class that inherits from ClientScenarioBase and mark test methods with [ClientScenario]:

using Zaldaryon.Pharos.XUnit;
using Xunit;

public class ChunkRenderingTests : ClientScenarioBase
{
    [ClientScenario]
    public void ClientLoadsChunksAroundPlayer()
    {
        Player!.SetPosition(0, 100, 0);
        Player.LookAt(32, 64, 32);
        FrameController!.Frames(60);
        Assert.True(Client!.WorldMap.LoadedChunks > 0);
    }
}

Quick Start: Server Scenarios

Inherit from ServerScenarioBase and use [ServerScenario]:

using Zaldaryon.Pharos.XUnit;
using Xunit;

[ServerWorld(seed: "12345", playStyle: "creativebuilding", worldType: "superflat")]
public class InventoryTests : ServerScenarioBase
{
    [ServerScenario]
    public async Task GivingItemToPlayer_UpdatesInventory()
    {
        var player = await CreateTestPlayerAsync("TestPlayer");
        player.GiveItem("game:sword-iron");
        Assert.True(player.HasItem("game:sword-iron"));
    }
}

Quick Start: Client-Server Scenarios

Combine both in one locked-step test with [ClientServerScenario]:

using Zaldaryon.Pharos.XUnit;
using Xunit;

public class BlockInteractionTests : ClientServerScenarioBase
{
    [ClientServerScenario]
    public async Task BreakingBlock_UpdatesBothSides()
    {
        var pos = new BlockPos(10, 64, 10);
        Server.Api.World.BlockAccessor.SetBlock(1, pos);
        await Session.StepUntilAsync(() => ClientServerAssert.BlockSynced(Session, pos));
        ClientServerAssert.ClientServerBlockSynced(Session, pos);
    }
}

Run tests with:

dotnet test -c Release

On Linux without a display:

./scripts/run-headless-linux.sh

Packages

Package Description
Zaldaryon.Pharos Core headless client bootstrap, frame stepper, and inspection APIs
Zaldaryon.Pharos.Bridge In-client mod exposing inspection hooks to scenario code
Zaldaryon.Pharos.XUnit xUnit integration: [ClientScenario], [ServerScenario], [ClientServerScenario]
Zaldaryon.Pharos.AtlasCompat Drop-in compatibility shim for Atlas.Api and Atlas.XUnit

Install Zaldaryon.Pharos.XUnit for client and server testing. Install Zaldaryon.Pharos.AtlasCompat to migrate existing Atlas test suites without code changes.

Platform Support

Platform Method Notes
Windows Hidden GLFW window with FBO Works on any GPU
Linux Mesa llvmpipe under Xvfb Works in CI without a GPU
macOS Not supported GLFW cannot create headless OpenGL contexts

Both Windows and Linux produce identical rendering behavior and report OpenGL 4.5 core profile.

Inspection APIs

Client rendering

Class Purpose
GlCommandProxy Count draw calls, buffer allocations, and VAO operations
CullingInspector Query which chunks are visible, frustum-culled, or occlusion-culled
MemoryInspector Track mesh pool hit/miss rates and type allocations
ShaderInspector Intercept uniform uploads and detect redundant state changes
FramebufferSnapshot Capture pixels for visual regression comparisons
IndirectDrawInspector Verify GPU indirect draw dispatch and command buffer contents

Server and network

Class Purpose
EmbeddedServerHost Native embedded server with tick control and sandbox isolation
ServerSandbox Isolated temp directory, mod staging, SQLite-safe cleanup
WorldSnapshot In-memory world state capture and rollback
PacketRecorder Record and replay deterministic server packet streams
PacketTracer Assert that specific packet IDs cross the loopback boundary
NetworkDegradationSimulator Inject latency, packet drop, and jitter

Assertions

Class Purpose
PharosAssert Client-side rendering assertions (draw collapse, chunk visibility, UV, GL leaks)
ClientServerAssert End-to-end block sync, position sync, inventory sync assertions

See the inspection API reference for method signatures and examples.

Documentation

Status

v0.3.0 complete. All 36 issues across milestones M1 through M14 are merged. Packages are available on NuGet. See the roadmap for the full history.

License

MIT

Support

If Pharos helps your mod development, consider supporting via Ko-fi.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Zaldaryon.Pharos.XUnit:

Package Downloads
Zaldaryon.Pharos.AtlasCompat

Drop-in compatibility shim for migrating from Pixnop.Atlas to Zaldaryon.Pharos.XUnit. Provides type aliases in Atlas.Api and Atlas.XUnit namespaces that delegate to native Pharos types.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.0 112 9/19/2026
0.3.0 97 9/18/2026