No description
  • C# 42.6%
  • TypeScript 13.9%
  • Rust 13.1%
  • HTML 10.7%
  • Python 10.6%
  • Other 9.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Meta Vens 0bfc85a4f2 JSON backing store, I/O fixes, Networking Security
Introduced Newtonsoft.Json-backed persistence.
Improved backing-store reliability and serialization across the caching stack.
Improved networking security posture.

Key changes:
- Add new GameCult.Caching.NewtonsoftJson project with SingleFile/MultiFile backing stores and polymorphic known-type envelopes.
- Add MessagePack helper serialization (DatabaseEntrySerialization) and update MessagePack backing stores to use the shared options/resolver; add DatabaseLink formatter and generator/analyzer docs.
- Update CultLib.sln to include the new projects and new caching tests project.
- Improve CultCache persistence behavior: track pending store operations, wait for operations on PullAll, and centralize async push handling with error logging.
- Harden file I/O in multi-file/single-file stores: atomic temp-file writes, safe Replace/Move semantics, rename-safe deletes, and improved file-watcher subscription and debounce disposal.
- Add README files and documentation for several subprojects and packaging projects.

These changes add JSON persistence support, improve serialization consistency, and make on-disk operations more robust and observable.
2026-04-18 13:01:24 +01:00
.vscode Initial commit 2026-04-18 06:04:39 +01:00
src JSON backing store, I/O fixes, Networking Security 2026-04-18 13:01:24 +01:00
tests JSON backing store, I/O fixes, Networking Security 2026-04-18 13:01:24 +01:00
.gitattributes Initial commit 2026-04-18 06:04:39 +01:00
.gitignore Initial commit 2026-04-18 06:04:39 +01:00
AGENTS.md JSON backing store, I/O fixes, Networking Security 2026-04-18 13:01:24 +01:00
CultLib.sln JSON backing store, I/O fixes, Networking Security 2026-04-18 13:01:24 +01:00
CultLib.txt Initial commit 2026-04-18 06:04:39 +01:00
Directory.Build.props Initial commit 2026-04-18 06:04:39 +01:00
LICENSE Initial commit 2026-04-18 06:04:39 +01:00
README.md JSON backing store, I/O fixes, Networking Security 2026-04-18 13:01:24 +01:00

CultLib

CultLib is a set of reusable C# libraries for game backends, game-adjacent services, and Unity-integrated tooling.

The libraries cover three main areas:

  • logging primitives and implementations
  • a typed in-memory cache with pluggable persistence
  • LiteNetLib-based networking with encrypted credential exchange and signed session tokens

Repository Scope

The solution includes:

  • GameCult.Logging: common logging abstraction plus console and file implementations
  • GameCult.Caching: DatabaseEntry-based cache, indexes, global entries, and backing-store abstractions
  • GameCult.Caching.MessagePack: MessagePack-backed persistence for the cache
  • GameCult.Caching.NewtonsoftJson: Newtonsoft.Json-backed persistence for the cache
  • GameCult.Caching.MessagePack.Generator: source generator for MessagePack formatters for cache models
  • GameCult.Caching.MessagePack.Analyzers: packaging project that delivers the generator to consuming projects
  • GameCult.Networking: encrypted login/register/verify flows and message dispatch over LiteNetLib
  • GameCult.Caching.Tests: NUnit tests for cache and backing-store behavior
  • GameCult.Networking.Tests: NUnit tests for networking behavior
  • GameCult.Unity: Unity-side project and integrations used with the runtime libraries

Repository Layout

src/
  GameCult.Logging/
  GameCult.Caching/
  GameCult.Caching.MessagePack/
  GameCult.Caching.NewtonsoftJson/
  GameCult.Caching.MessagePack.Generator/
  GameCult.Caching.MessagePack.Analyzers/
  GameCult.Networking/
  GameCult.Unity/
tests/
  GameCult.Caching.Tests/
  GameCult.Networking.Tests/

Build

dotnet build CultLib.sln

Test

dotnet test CultLib.sln

Common Concepts

DatabaseEntry

The cache-centric libraries revolve around DatabaseEntry. Every entry has a stable Guid identifier and can optionally:

  • expose a human-readable name through INamedEntry
  • participate in generic indexes registered at runtime
  • be treated as a global singleton entry through GlobalSettingsAttribute

Typical entry shape:

using GameCult.Caching;

public class ItemData : DatabaseEntry, INamedEntry
{
    public string Name = string.Empty;
    public int Value;

    public string EntryName
    {
        get => Name;
        set => Name = value;
    }
}

CultCache and Backing Stores

CultCache is an in-memory index over DatabaseEntry objects. It can operate entirely in memory, or it can be attached to one or more backing stores for persistence and synchronization.

  • the cache is the query surface
  • backing stores are persistence adapters
  • indexes and name maps are maintained inside the cache, not inside the store

Important: Multiple Backing Stores

When multiple backing stores are added, behavior depends on how they are registered.

If a store is added with domain types:

cache.AddBackingStore(playerStore, typeof(PlayerData));
cache.AddBackingStore(settingsStore, typeof(AppSettings));

then that store becomes the direct persistence target for those types.

If a store is added without domain types:

cache.AddBackingStore(primaryStore);
cache.AddBackingStore(mirrorStore);

then the first generic store acts as the primary writable store for non-domain-specific entries. Additional generic stores subscribe to the existing stores and mirror their change events.

Implications:

  • order matters for generic stores
  • AddAsync writes to the type-specific store when one exists
  • otherwise AddAsync writes to the first generic store
  • later generic stores do not become co-primaries; they mirror earlier stores
  • PullAllBackingStoresAsync pulls from every registered store

Recommended patterns:

  • use one generic primary store if you want simple persistence
  • use domain-specific stores when different entry types belong in different persistence layers
  • treat additional generic stores as mirrors or downstream replicas, not independent write targets

Example: Cache + Networking

using GameCult.Caching;
using GameCult.Logging;
using GameCult.Networking;

var cache = new CultCache
{
    Logger = new ConsoleLogger()
};

var server = new Server(cache)
{
    Logger = new ConsoleLogger()
};

server.Start();

Secrets and Runtime Configuration

GameCult.Networking uses two pieces of deployment configuration:

  • GAMECULT_CONNECTION_KEY
  • GAMECULT_SESSION_SIGNING_SECRET

Production guidance:

  • set both values before starting the server
  • treat GAMECULT_CONNECTION_KEY as shared client/server protocol configuration
  • treat GAMECULT_SESSION_SIGNING_SECRET as a server-only secret
  • generate high-entropy random values and store the server-side value in your platform's secret store
  • do not rely on local-development defaults in production
  • partial configuration is rejected at startup

Recommended value format:

  • at least 32 random bytes per value
  • encode as Base64 or Base64Url if you want a portable text representation

Example secret generation in PowerShell:

[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))

Typical production setup patterns:

  • inject GAMECULT_SESSION_SIGNING_SECRET and the server copy of GAMECULT_CONNECTION_KEY as environment variables from Docker secrets, Kubernetes secrets, systemd environment files, or your cloud secret manager
  • ship the matching GAMECULT_CONNECTION_KEY to the client through a build-generated config asset, code-generated constants, or another explicit client configuration mechanism
  • scope them per environment so development, staging, and production do not share values
  • rotate GAMECULT_SESSION_SIGNING_SECRET operationally
  • treat GAMECULT_CONNECTION_KEY as versioned protocol config; changing it requires a coordinated client/server rollout

Example server startup with strict environment validation:

using GameCult.Caching;
using GameCult.Networking;

var cache = new CultCache();
var security = ServerSecurityOptions.FromEnvironment();
var server = new Server(cache, security);

Example local-development server startup:

using GameCult.Caching;
using GameCult.Networking;

var cache = new CultCache();
var security = ServerSecurityOptions.Development();
var server = new Server(cache, security);

Example shipped-client startup with explicit client configuration:

using GameCult.Networking;

var security = new ClientSecurityOptions("<matching-connection-key>");
var client = new Client(security);

Project Docs

Each subproject has a local README with package-specific detail: