Repository navigation
Releases
Releases · ValveResourceFormat/ValveKeyValue
v0.80.0
Immutable
release. Only release title and notes can be modified.
- Breaking: typed deserialization now runs the public parameterless constructor, so initializers apply to missing keys.
- Breaking: typed
KVSerializermethods are marked[RequiresUnreferencedCode]/[RequiresDynamicCode]; useKVObjectorKVDocumentwhen trimming or with AOT. - Faster hex blob parsing, indentation writing and number parsing.
v0.73.0
Immutable
release. Only release title and notes can be modified.
- Added packed typed arrays:
KVObject.PackedArray(T[] values, KVFlag elementFlag)forbool,short,ushort,int,uint,long,ulong,floatanddoublestores the values directly, without aKVObjectper element - Added
KVObject.IsPackedArray - Added
KVObject.TryGetArraySpan<T>()to read a packed array's values without copying - Added
KVObject.ToArray<T>()andKVObject.GetElement<T>(index)to convert array elements, matching the explicit cast operators - Added
KVObject.Elementsto get array elements as anIReadOnlyList<KVObject> - Reading a packed array through the indexer,
foreach,Values,ChildrenorElementskeeps it packed;AsArraySpan,AddandRemoveAtconvert it to elements - Reduced allocations when reading and writing: no LINQ, no boxed enumerators, pooled reader and builder states, and number formatting without allocating strings
v0.72.0
Immutable
release. Only release title and notes can be modified.
- Breaking: KV3 text quoted values are always strings, so
"42"and"true"no longer become numbers or bools - Breaking: KV3 text parsing is stricter and throws on: a missing
=after a key, missing commas between array elements (a trailing comma is still allowed), unquoted values that are not booleans, null, numbers,nanorinf, unquoted keys that are not identifiers, unquoted non-ASCII tokens, blob bytes that are not separate hex pairs, and header names that are quoted or an encoding other thantext - Breaking: KV3 multi-line strings only end at
"""at the start of a line that does not follow a backslash - Breaking: KV1 text
=,{and}end unquoted keys and values, soa=breads as keyawith valueb - Breaking: KV1 text
#includeand#baseare directives only outside the root object (before or after it); inside an object they are ordinary keys, and other#values are plain strings instead of throwing - Breaking: KV1 text throws on two consecutive conditionals, and when a pair has several conditionals the last one decides
- Added KV1 text
=assignments (key = value), with conditions allowed on either side of= - Added KV1 binary wide strings and binary blobs, which used to throw
NotSupportedException - Added
KVFlag.Localizefor the KV3localize:flag - KV1 binary accepts both end markers regardless of header
- KV3 text parses
true,falseandnullin any case, floats with a leading decimal point, and a lone+as zero - KV3 text allows whitespace and comments around flags,
#blobs, blob bytes and header tokens, and//comments continue onto the next line after a trailing backslash - KV3 multi-line strings unescape
\"""and normalize CRLF to LF - KV3 text writer matches Valve's formatting: apostrophes in quoted keys are not escaped, and a flagged root object's
{goes on its own line - Source maps report KV1 text
=asAssignment, and unquoted KV3 tokens asIdentifier - Fixed KV3 text writer copying the input document's encoding into the header instead of
text - Fixed KV3 text parser looping forever on a stray
;,:or| - Fixed KV3 text writer producing unreadable multi-line strings for values ending in a backslash or carriage return
v0.71.0
Immutable
release. Only release title and notes can be modified.
- Breaking: Throw on documents with multiple root objects (KV1 text, KV1 binary, KV3) instead of misparsing
- Breaking: Malformed input now consistently throws
KeyValueExceptioninstead ofInvalidDataException/InvalidOperationException - Breaking: Parse KV1 hex numbers like Valve does (only lowercase
0xprefix) - Breaking: Condition variables are now case-insensitive
- Breaking: Throw when deserializing into unsupported enumerable types
- Breaking: Invalid enum values throw
NotSupportedException - Added
SerializeWithSourceMap<T> - Added public
KVFlag.SerializeFlagName()extension - Added enum deserialization from names (including flags) in collections, dictionaries and lookups
- Improved exception messages to include line and column
- Suggest enabling escape sequences if parsing fails on
\" - Rewrote
KVConditionEvaluatorto match Valve's implementation - Serialize
charanddecimalproperties as scalars - Skip get-only properties when deserializing
- Skip record
EqualityContractand indexer properties - Fixed
KVObject.ToString()andToType()to default to invariant culture - Fixed circular reference detection to use reference equality
- Fixed stray trailing bracket not throwing
- Fixed
KVObjectandKVDocumentvalues being reflected over when serializing typed objects
v0.70.0
Immutable
release. Only release title and notes can be modified.
- Do not sort object members by name (.NET 7 makes this declaration order)
- Add (de)serialize mode that produces sourcemaps for syntax highlighting
v0.65.0
Immutable
release. Only release title and notes can be modified.
- Breaking: Make KVDocument standalone
- Added Root property
- Added string indexer and implicit cast to KVObject for backwards compatibility, but you should use Root.
- Breaking: Remove AsSpan (returned blobs), add AsArraySpan for getting KV3 arrays
- Make root name and header nullable
v0.60.0
Immutable
release. Only release title and notes can be modified.
- Breaking: Made string indexer throw on unknown key, removed GetChild
- Breaking: Made casting null to string throw
- Breaking: Made casting null byte[] throw
- Breaking: Made (string null) constructor throw
- Breaking: Made this[int] throw on dictionaries
- Breaking: Made Remove/Clear on non-collections throw
- Breaking: Made setting null create a null object instead of removing
- Breaking: Enabled nullable annotations
- Added SkipHeader option for KV3
- Added support for (de)serializing into nullables
- Added support for read-only collection and dictionary interface types
- Added missing (u)short constructors
- Added byte[] explicit operator
- Added To* methods without formatter
- Added TryAdd
- Added IsCollection
- Fixed Nullable deserialization/serialization
- Fixed Add to throw on existing keys in dictionaries
- Fixed Add methods to not store raw nulls
- Fixed ToString() on null type return a "null" string
v0.51.0
Immutable
release. Only release title and notes can be modified.
- KVObject fields are now readonly (immutable after construction)
- Scalar type conversions now use checked casts (throws OverflowException instead of silent truncation)
- ToBoolean() explicitly supports integer/float/string types, throws for Collection/Array/Blob
- KVObject implements IReadOnlyDictionary<string, KVObject> instead of IEnumerable<KeyValuePair<string, KVObject>>
- Add Collection(capacity), ListCollection(capacity), Array(capacity) overloads
- Fix UInt64 conversions for ToDecimal, ToDouble, ToSingle
- Fix peeked value unboxing in KV3 token reader
- Throw on unclosed comments and invalid hex in KV3
- Optimize text/binary string writing
- Reuse StringBuilder and use SearchValues for faster scanning
v0.50.0
Immutable
release. Only release title and notes can be modified.
BREAKING CHANGES: This release is a second pass at improving the overall API. If you run into issues or unergonomic API, open a new issue.
- Merged KVValue into KVObject, this is now a single type.
- Name removed from KVObject, keys are stored in the parent container. Use KVDocument.Name for the root key name.
- Iteration yields KeyValuePair<string,KVObject> instead of KVObject.
- KVDocument is now the return type of Deserialize(), holding the root Name and Header.
- Added Keys and Values properties on KVObject
- Added KVObject.ListCollection(IEnumerable) factory for creating list-backed collections from existing data
- Added Implicit operators for byte and sbyte
v0.40.0
Immutable
release. Only release title and notes can be modified.
BREAKING CHANGES: This release changes how the API works to make it easier to iterate and modify values. If you run into issues or unergonomic API, open a new issue.
- Replaced KVArrayValue, KVCollectionValue, KVBinaryBlob, KVNullValue classes with a single KVValue readonly record struct (scalars stored inline, no boxing)
- KVObject string/int indexers now return KVObject instead of KVValue
- KVObject string indexer setter now takes KVObject instead of KVValue (implicit conversions from primitives)
- Added dictionary-backed collections for KV3 (KVObject.Collection()) with O(1) lookup
- Added KVObject.ListCollection() for explicit list-backed collections (KV1 duplicate key support)
- Added KVObject.Array() and KVObject.Blob() static factory methods
- Added TryGetChild(string, out KVObject)
- KVObject now implements IConvertible, Convert.ChangeType() works on indexer results
- KVValue.Flag is now init-only (use with expression to modify)
- Removed ChildrenValues property
- Renamed AddProperty to Add(string, KVValue)
- Typed deserialization now supports KV3 native arrays (List, T[], etc.)
- Typed deserialization now supports byte[] properties from binary blobs
- Typed deserialization now supports enum properties
- SetChild on list-backed collections now replaces in-place instead of remove + append