Paradise.BLOB
0.47.0
dotnet add package Paradise.BLOB --version 0.47.0
NuGet\Install-Package Paradise.BLOB -Version 0.47.0
<PackageReference Include="Paradise.BLOB" Version="0.47.0" />
<PackageVersion Include="Paradise.BLOB" Version="0.47.0" />
<PackageReference Include="Paradise.BLOB" />
paket add Paradise.BLOB --version 0.47.0
#r "nuget: Paradise.BLOB, 0.47.0"
#:package Paradise.BLOB@0.47.0
#addin nuget:?package=Paradise.BLOB&version=0.47.0
#tool nuget:?package=Paradise.BLOB&version=0.47.0
Paradise.BLOB
Paradise.BLOB builds immutable unmanaged data with Unity-style blob primitives in plain .NET. Declare an unmanaged struct; a builder writes contiguous bytes with relative offsets, and a reader exposes the struct over those bytes without parsing or copying.
Used by collision worlds, behavior trees, mesh blobs, skeletons and animation clips.
Install
dotnet add package Paradise.BLOB
Features
- Build immutable unmanaged roots with
ValueBuilder<T>andStructBuilder<T>. - Store arrays, strings, pointers, trees, sorted arrays, and dynamically typed payloads — including arrays whose elements themselves hold arrays and strings.
- Read blobs from one aligned native copy (
NativeBlobAssetReference<T>) or over a pinned managed array (ManagedBlobAssetReference<T>). - Keep offsets and alignment correct without hand-rolling binary layouts.
- Supports .NET and NativeAOT without reflection.
Quick start
using Paradise.BLOB;
using System.Text;
public struct DemoBlob
{
public BlobString<UTF8Encoding> Name;
public BlobArray<int> Values;
public BlobPtr<int> MaxValue;
}
var builder = new StructBuilder<DemoBlob>();
builder.SetString(ref builder.Value.Name, "demo");
builder.SetArray(ref builder.Value.Values, new[] { 1, 2, 3 });
builder.SetPointer(ref builder.Value.MaxValue, 3);
byte[] bytes = builder.CreateBlob(); // what you store, ship or hash
using var blob = new NativeBlobAssetReference<DemoBlob>(bytes); // one aligned copy, no pinning
ref var root = ref blob.Value;
Console.WriteLine(root.Name.ToString());
Console.WriteLine(string.Join(", ", root.Values.ToArray()));
Console.WriteLine(root.MaxValue.Value);
Reading: native or managed
NativeBlobAssetReference<T>(ReadOnlySpan<byte>, int alignment = 16)makes one aligned native copy, with no GC pinning. Prefer it at runtime; the input can be a file read or a larger span's slice. Dispose it after upload or use; a finalizer frees undisposed memory.ManagedBlobAssetReference<T>(byte[])pins a managed array in place and reads through the pin. Use it when the bytes must stay abyte[]you also hand elsewhere. Dispose it, or the array stays pinned.
Both hand back ref T Value — a reference into the blob, not a copy.
Nested layouts: arrays of structs that hold arrays
An element type may itself carry BlobArray<T> and BlobString<TEncoding> fields. Build such an array from one builder per element:
public struct Draw
{
public uint FirstIndex;
public uint IndexCount;
public BlobString<UTF8Encoding> Name;
}
public struct MeshBlob
{
public uint Magic;
public uint Version;
public BlobArray<float> Vertices;
public BlobArray<Draw> Draws;
}
var mesh = new StructBuilder<MeshBlob>();
mesh.Value.Magic = 0x48534D50; // "PMSH"
mesh.Value.Version = 1;
mesh.SetArray(ref mesh.Value.Vertices, vertices);
mesh.SetArray(ref mesh.Value.Draws, draws.Select(d =>
{
var draw = new StructBuilder<Draw>();
draw.Value.FirstIndex = d.First;
draw.Value.IndexCount = d.Count;
draw.SetString(ref draw.Value.Name, d.Name);
return (IBuilder<Draw>)draw;
}));
Conventions the engine's formats follow
- Magic and version first. The first two fields of a root are a
uintmagic and auintversion, so a reader can refuse a foreign or newer blob by name before touching an offset. Check them on the bytes (BitConverter.ToUInt32(bytes)) before constructing a reference. - Validate after opening. Before indexing trusted blob memory, check required counts and indices, such as draw ranges and joint indices. Dispose the reference before throwing on invalid data.
- Deterministic bytes. The same input builds the same bytes, so a blob can live in a source tree beside what it was made from and be fingerprinted by hash.
Read blob headers by reference
BlobArray<T>, BlobString<TEncoding> and BlobPtr<T> hold offsets relative to their own address. Copying a header makes its offset point outside the blob, silently returning wrong data. Avoid these accidental copies:
// WRONG: `in` makes `blob` a readonly reference; calling a non-readonly member on
// blob.Draws forces a defensive COPY of the array header.
static void Check(in MeshBlob blob) { var n = blob.Draws[0].IndexCount; }
// WRONG: a `readonly` member on the struct does the same to every array it touches.
public readonly float FirstVertex => Vertices[0];
// WRONG: passing a BlobString (or BlobArray) by value to a helper.
static string? NameOf(BlobString<UTF8Encoding> name) => name.ToString();
Do this instead:
static void Check(ref MeshBlob blob) { ref var draw = ref blob.Draws[0]; var n = draw.IndexCount; }
public float FirstVertex => Vertices[0]; // mutable receiver
var name = node.Name.ToString(); // read in place
Access relative-offset data through a mutable ref; avoid readonly receivers and by-value helpers.
Common builders
ArrayBuilder<T>andSetArray(...)for contiguous unmanaged arrays.ArrayBuilderWithItemBuilders<T>and theSetArray(ref field, IEnumerable<IBuilder<T>>)overload for arrays of structs that hold arrays or strings.StringBuilder<TEncoding>andSetString(...)for encoded blob strings.PtrBuilderWithNewValue<T>andSetPointer(...)for blob pointers.TreeBuilder<T>andAnyTreeBuilderfor preordered trees with subtree end indices.SortedArrayBuilder<TKey, TValue>for hash-ordered key/value lookup tables.
Notes
- Blob roots and referenced values must be unmanaged.
CreateBlob()returns the raw serialized bytes for storage or transport;CreateNativeBlobAssetReference()andCreateManagedBlobAssetReference()open them directly.- Dispose every reference: a native one frees its memory, a managed one unpins its array.
| 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
- No dependencies.
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Paradise.BLOB:
| Package | Downloads |
|---|---|
|
Paradise.BT
Pure .NET behavior tree runtime inspired by EntitiesBT. |
|
|
Paradise.Physics
Stateless collision/physics query library for Paradise Engine: static colliders, raycasts and shape casts with no caches and no hidden state. |
|
|
Paradise.Assets.Mesh
The Paradise mesh blob: GPU-ready interleaved geometry with draw records as a Paradise.BLOB layout, read at runtime by pinning the bytes the asset pipeline extracted from a GLB. No glTF, no JSON, no images. |
|
|
Paradise.Animation
Skeletal animation runtime and offline builder in managed code, using ozz-animation's archive format: load an ozz skeleton and clips, sample a clip into local poses and model-space matrices; build, optimize and save the same archives from raw keyframes. No native code. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.47.0 | 40 | 9/10/2026 |
| 0.46.3 | 76 | 9/9/2026 |
| 0.46.2 | 73 | 9/9/2026 |
| 0.46.1 | 76 | 9/9/2026 |
| 0.46.0 | 85 | 9/9/2026 |
| 0.45.1 | 114 | 9/8/2026 |
| 0.45.0 | 125 | 9/8/2026 |
| 0.44.0 | 130 | 9/8/2026 |
| 0.42.0 | 157 | 9/7/2026 |
| 0.41.0 | 164 | 9/6/2026 |
| 0.40.0 | 182 | 9/6/2026 |
| 0.39.0 | 168 | 9/6/2026 |
| 0.38.0 | 151 | 9/5/2026 |
| 0.37.0 | 150 | 9/5/2026 |
| 0.36.0 | 154 | 9/4/2026 |
| 0.35.0 | 131 | 9/3/2026 |
| 0.34.1 | 126 | 9/3/2026 |
| 0.34.0 | 133 | 9/2/2026 |
| 0.33.0 | 120 | 9/1/2026 |
| 0.32.0 | 121 | 9/1/2026 |