Class XnbWriter
- Namespace
- ShadowDusk.Core
- Assembly
- ShadowDusk.Core.dll
Wraps a compiled effect payload in the XNA/MonoGame XNB content container, so a
consumer can drop the file where their mgfxc-built .xnb used to sit and keep
calling Content.Load<Effect>("Foo") without changing a line of code
(issue #199, Phase 60).
This writer is deliberately only a container. The payload it wraps is the exact
.mgfx / .knifx / .fxb ShadowDusk already produces and has render-proven,
so no shader-compilation behaviour changes and no existing output byte moves. It is pure
managed code with no native dependency, so it runs on every host including WASM and Android.
Byte layout (uncompressed single-effect asset), measured from real
dotnet-mgcb 3.8.4.1 output for /platform: Windows, DesktopGL, Android, iOS and
MacOSX — not transcribed from documentation:
'X' 'N' 'B' magic
<platform> one of the runtime's accepted identifiers (see PlatformIdentifierFor)
0x05 format version
0x00 flags (bit 0x80 = LZX, 0x40 = LZ4; this writer emits uncompressed)
int32 TOTAL file size, header included
7-bit type-reader count (always 1 for an effect)
7-bit reader name length
bytes reader name (EffectReaderTypeName)
int32 reader version (0)
7-bit shared-resource count (0)
7-bit type id of the primary object (1 = 1-based index into the readers)
int32 payload length
bytes the effect payload, verbatim
public static class XnbWriter
- Inheritance
-
XnbWriter
- Inherited Members
Fields
EffectReaderTypeName
The type-reader manifest entry for an effect, byte-identical to what mgcb
writes.
The embedded assembly version is deliberate and is deliberately ignored by every consumer runtime. All three strip it before resolving the reader, but they do not strip it the same way, and the intersection of their rules is exactly this string:
- MonoGame (
ContentTypeReaderManager.PrepareType) only runs its version-stripping regex when the name containsPublicKeyToken— so the token must be present even though its value is irrelevant. - FNA matches one compiled regex requiring the full
, <assembly>, Version=…, Culture=…, PublicKeyToken=…triple, and requires the assembly to be one ofMicrosoft.Xna.Framework[.Graphics|.Video]orMonoGame.Framework. A bare…, MonoGame.Frameworkwith no version does not match, and FNA would then fail to resolve the reader. - KNI is a MonoGame fork and consumes stock
mgcboutput, which is this string.
So the version number here is inert, but the shape around it is load-bearing.
Emitting exactly what mgcb emits is the choice that cannot be wrong: every
.xnb in every shipped MonoGame game already carries it.
public const string EffectReaderTypeName = "Microsoft.Xna.Framework.Content.EffectReader, MonoGame.Framework, Version=3.8.4.1, Culture=neutral, PublicKeyToken=null"
Field Value
FormatVersion
XNB container format version. MonoGame's ContentManager accepts 4 or 5 and throws
"Invalid XNB version" otherwise; mgcb writes 5.
public const byte FormatVersion = 5
Field Value
Methods
PlatformIdentifierFor(PlatformTarget)
Returns the XNB platform identifier byte for target.
Derived from the target the consumer already picked — never asked for. The
standing seamlessness directive forbids making a consumer opt in to get correct output,
and measurement showed no opt-in is needed: MonoGame's ContentManager and FNA's
both validate this byte only for membership in a whitelist, never against the
platform actually running, so a correctly-derived byte always loads.
FNA's whitelist is the binding constraint and is smaller than MonoGame's: it
has no 'V' (DesktopVK) and no 'G' (DirectX 12), which is why
Fna maps to 'w' — the XNA Windows identifier, present
in both lists.
public static char PlatformIdentifierFor(PlatformTarget target)
Parameters
targetPlatformTargetThe platform backend the payload was compiled for.
Returns
Exceptions
- ArgumentOutOfRangeException
targethas no XNB platform identifier. Unreachable through the compiler: Metal is the only such target and the pipeline already rejects it withSD0200long before any bytes exist to wrap.
Wrap(ReadOnlySpan<byte>, PlatformTarget)
Wraps effectPayload in an XNB container for target,
deriving the platform identifier with PlatformIdentifierFor(PlatformTarget).
public static byte[] Wrap(ReadOnlySpan<byte> effectPayload, PlatformTarget target)
Parameters
effectPayloadReadOnlySpan<byte>The compiled effect bytes — a
.mgfx,.knifx, or FNA.fxb. Written verbatim; this writer never inspects or rewrites the payload.targetPlatformTargetThe platform backend the payload was compiled for.
Returns
- byte[]
The complete
.xnbfile bytes.
Wrap(ReadOnlySpan<byte>, char)
Wraps effectPayload in an XNB container using an explicit platform
identifier. Prefer the PlatformTarget overload; this one exists for the
validation drivers, which must be able to produce a byte the derivation would not choose
in order to prove the runtime's acceptance rules.
public static byte[] Wrap(ReadOnlySpan<byte> effectPayload, char platformIdentifier)
Parameters
effectPayloadReadOnlySpan<byte>The compiled effect bytes, written verbatim.
platformIdentifiercharThe XNB platform identifier character.
Returns
- byte[]
The complete
.xnbfile bytes.