github markus-wa/demoinfocs-golang v6.0.0-rc.0

pre-release2 hours ago

Go Get

go get -u github.com/markus-wa/demoinfocs-golang/v6/pkg/demoinfocs@v6.0.0-rc.0

To upgrade from v5, this may be useful to update import paths (use at your own risk):

sed -i 's/demoinfocs-golang\/v5/demoinfocs-golang\/v6/' **/*.go

This is the first release candidate of v6. These notes are self-contained: they list every change since v5.2.0, so you don't need to read the alpha release notes to migrate from v5. If you are on an alpha, the per-alpha notes are linked at the end.

The v5 line continues to be maintained on the v5 branch for users not ready to upgrade. Fixes marked "also on the v5 branch" below are there too (unreleased as of this rc).

Upgrading from v5

Most of the API changes are mechanical. This table maps v5.2.0 code to v6; the sections below have the details and the PR links.

v5.2.0 v6.0.0-rc.0
github.com/markus-wa/demoinfocs-golang/v5/... github.com/markus-wa/demoinfocs-golang/v6/...
Go 1.24 Go 1.27
NewParserWithConfig(r, cfg), ParseWithConfig(r, cfg, cb) NewParser(r, option.X(...), ...) — one option function per former ParserConfig field: option.MsgQueueBufferSize(n), option.AdditionalNetMessageCreators(m), option.IgnoreErrBombsiteIndexNotFound(true), option.DisableMimicSource1Events(true), option.Source2FallbackGameEventListBin(b), option.IgnorePacketEntitiesPanic(true)
DefaultParserConfig, ParserConfig.Format gone — no options = the same defaults as before, the format is detected
Parse(r, cb) p := NewParser(r) + p.ParseToEnd(ctx)
ParseFile(path, cb), ParseFileWithConfig(path, cfg, cb) ParseFile(ctx, path, cb, option.X(...))
NewCSTVBroadcastParser(url), ParseCSTVBroadcast(url, cb), cfg.CSTVTimeout = d r, err := cstv.NewReader(ctx, url, cstv.WithTimeout(d), cstv.WithHTTPClient(c)) + NewParser(r)
p.ParseToEnd() p.ParseToEnd(ctx)
p.Cancel(), err == ErrCancelled cancel the ctx, errors.Is(err, context.Canceled)
panic(...) inside a handler to stop parsing cancel the ctx (context.WithCancelCause) — a panic in a handler is now re-raised on the caller as *PanicError
demoinfocs.Parser, GameState, GameRules, Participants (interfaces) *demoinfocs.Parser, *GameState, *GameRules, Participants (value)
sendtables.Entity, Property, ServerClass (interfaces), sendtablescs2.X *sendtables.Entity, *sendtables.Property, *sendtables.ServerClass, sendtables.X
fake.NewParser(), sendtables/fake your own small interface + fake, see examples/mocking
Equipment.UniqueID2() (ULID), GrenadeProjectile.UniqueID() / Inferno.UniqueID() (int64) UniqueID() returning common.UniqueID (uint64) on all three; .Uint64() for the number. IDs stored from v5 won't match
entity.Property("m_vecX") and other bare names that exist in several send-nodes of a class the send-node-prefixed name: m_vecVelocity.m_vecX, m_vecViewOffset.m_vecX, … (unique names like m_iHealth are unaffected)
Equipment.AmmoInMagazine() + 1 workarounds remove them, the off-by-one is fixed
PlayerHurt.HealthDamageTaken to reproduce HLTV ADR PlayerHurt.HealthDamage (HealthDamageTaken is now the HP actually removed, see below)
BombDropped.EntityID (was the player's entity ID) the C4's entity ID; the player's is BombDropped.Player.EntityID
protoregistry / anypb lookups of CSVCMsg_ServerInfo etc., msg.File_<x>_proto com.github.markus_wa.demoinfocs_golang.v6.CSVCMsg_ServerInfo, msg.File_v6_<x>_proto (Go types unchanged)
go run ./examples/print-events cd examples && go run ./print-events (own module)
events.BomsiteUnknown events.BombsiteUnknown (the misspelled alias still works)

Observable output also changes without any code change on your side: PlayerHurt.Health() & HealthDamageTaken, PlayerFlashed pairing, BombExplode on server shutdown, GrenadeEvent.Grenade attribution, InfernoStart timing, duplicate POV grenade events, and the order of Player.Weapons() and round-end projectile destruction are all different. The "Breaking Changes" section says how.

Breaking Changes

  • Upgraded version from v5 to v6, changing import paths from github.com/markus-wa/demoinfocs-golang/v5/... to github.com/markus-wa/demoinfocs-golang/v6/... in #686
  • Now requires Go 1.27 (up from 1.24) by @markus-wa in #681
  • Single NewParser constructor with functional options & context.Context, Cancel() removed by @markus-wa in #724
    • NewParser(r io.Reader, opts ...option.Option) is the only constructor. ParserConfig, DefaultParserConfig and all *WithConfig variants are replaced by the new option package (option.NetMessageDecryptionKey(key), option.UserCmdParsing(option.UserCmdParsingFull), …), with the same defaults as before
    • ParseToEnd(ctx) & ParseFile(ctx, path, cb, opts...) take a context: cancel it instead of calling Cancel(), check errors.Is(err, context.Canceled) instead of ErrCancelled. A cancellation that happens while the message queue drains is now returned too, instead of silently giving incomplete data
    • CSTV broadcasts are just an io.Reader: r, err := cstv.NewReader(ctx, url, cstv.WithTimeout(d), cstv.WithHTTPClient(c)), then NewParser(r). NewCSTVBroadcastParser/ParseCSTVBroadcast are gone. A non-200 response to the initial requests now returns cstv.ErrUnexpectedStatus instead of a confusing JSON error or an error page in the demo stream
  • Concrete types instead of interfaces ("accept interfaces, return structs") by @markus-wa in #725
    • *demoinfocs.Parser, *GameState, Participants (value) and a live *GameRules (a value fetched before the CCSGameRulesProxy entity exists no longer keeps a nil Entity() forever)
    • sendtablescs2 is merged into sendtables; Entity, Property, ServerClass and ServerClasses are concrete types (*sendtables.Entity etc., Property() returns nil if not found)
    • The ifacemaker-generated interfaces and both fake packages are removed (no more testify in your build); examples/mocking shows how to define your own small interface + fake
    • Entity.Destroy, Entity.Get, Exists, the Get* getters and Map are unexported or removed; Entity.String(), ServerClasses.String() and Entity.Replaced() are newly exported
  • Errors instead of panics by @markus-wa in #729, #730 and #732
    • The library's own failures are returned from ParseToEnd/ParseNextFrame: ErrUnexpectedEndOfDemo for truncated demos, *DecodeError / ErrDecodeFailed (with Frame, Cause & Stack) for corrupt data, unsupported schemas and missing properties (incl. PropertyValueMust calls inside your handlers), and reading demo: … for errors from your io.Reader
    • A panic in one of your handlers is re-raised on the caller's goroutine as *PanicError (original stack kept, recoverable) instead of being returned as an error string. To stop parsing from a handler, cancel the context (context.WithCancelCause) instead of panicking. Calling a parse method again afterwards returns ErrParserStopped
    • Hardened against corrupt input: frames are capped at 16 MiB (64 MiB for DEM_AnimationData), field indices & collection sizes at 65536, plus per-parse budgets for entity state. Exceeding a limit returns ErrDecodeFailed instead of allocating gigabytes or hanging forever. Broken DEM_FullPacket frames are skipped with a ParserWarn (WarnTypeBrokenFullPacket), as the game does (#409); a corrupt frame of any other type is now ErrDecodeFailed instead of a warning + empty message. Fuzz targets and a corrupt-demo corpus are part of the test suite now
    • option.IgnorePacketEntitiesPanic now actually dispatches ParserWarn{Type: WarnTypePacketEntitiesPanic, Err} (it used to print to stderr) and no longer swallows user panics; events.ParserWarn has a new Err field
    • NewParser no longer reads from the stream, read errors surface from ParseToEnd/ParseNextFrame; Close() closes the stream even before parsing. PropertyValueMust panics with *sendtables.PropertyNotFoundError instead of a string
  • Player.Name & Player.SteamID64 now come from the CS2 player controller (CCSPlayerController.m_iszPlayerName / m_steamID, i.e. the server-enforced scoreboard name) by @markus-wa in #710 — fixes names being reverted after a reconnect (#692, FACEIT names on broken_1.dem), keeps player_changename renames and plugin prefixes like "COACH E"
    • The Steam / connect name stays available via PlayerInfo & PlayerConnect
    • A slot taken over by a different person gets a new *Player; the previous occupant gets PlayerDisconnected, IsConnected = false & Entity = nil. An existing player's SteamID64 is never changed. Playing() no longer returns the same *Player twice when a bot name is re-used (#693)
    • PlayerInfo & StringTablePlayerUpdateApplied only fire when a slot's info actually changes; PlayerNameChange comes from controller updates and is not dispatched for bots, unknown → name, or placeholder names (empty / SteamID64)
    • Player.IsBot is m_steamID == 0, Player.Team is set on creation, raw userinfo is kept after disconnect
    • New sendtables.Entity.OnUpdateFinished(func()): the parser applies controller changes there, so inside your own CCSPlayerController prop handlers the bound Player isn't updated yet, read it from an OnUpdateFinished delegate instead
    • Also fixes string-table entry index decoding (indices are relative, not absolute): 18 of 72 demos had userinfo entries attributed to the wrong slot (up to ~25k per demo)
    • Verified on 60 demos: name mismatches vs. the controller 1.67M → 0, duplicate *Players in Playing() 0 → 0, kills identical
  • common.UniqueID replaces Equipment.UniqueID2() and the int64 IDs of GrenadeProjectile / Inferno by @markus-wa in #712 (with @AdamMagued, #711) — one uint64 counter type for all three, comparable with < and sorted in creation order. String() / JSON is the decimal number instead of a 26-character ULID, so IDs stored from earlier versions won't match. oklog/ulid is no longer a dependency
  • Entities leaving & re-entering the PVS by @markus-wa in #740 and #746 (#728, #741, #742)
    • New Entity.InPVS(), Entity.OnLeavePVS(func()) & Entity.OnEnterPVS(func()). A weapon that left the PVS stays in GameState().Weapons() with its Owner until it is destroyed or comes back
    • A same-serial re-create (PVS re-entry) keeps the same *Entity: entity handlers see EntityOpUpdated|EntityOpEntered instead of Created|Entered, ServerClass.OnEntityCreated doesn't fire again, and property handlers fire only for values that changed
    • POV demos no longer emit duplicate GrenadeProjectileThrow, grenade WeaponFire & InfernoStart events for projectiles / infernos that re-enter the PVS (pov.dem: 904 → 315 throws, 253 → 86 inferno starts; GOTV output is byte-identical)
  • Ambiguous bare sendtable field names no longer resolve by @akiver in #674 and @markus-wa in #706 — e.g. m_vecX on a player pawn silently returned the view offset, not the velocity. Use the send-node-prefixed name (m_vecVelocity.m_vecX, m_vecViewOffset.m_vecX, m_AttributeManager.m_Item.m_NetworkedDynamicAttributes.m_Attributes, …). Names that are unique within their class (m_iHealth etc.) are unaffected
  • PlayerHurt.HealthDamageTaken is now the HP actually removed (health before the hit minus reported post-hit health) by @markus-wa in #700 (and #663 for fatal hits)
    • On many demos a hit removes dmg_health or dmg_health + 1 HP. This depends on the server build: it shows up on demos from 2023 to 2026, but not on all of them. HealthDamageTaken now matches the game's own damage stats (m_pActionTrackingServices.m_iDamage, round_stats in server.log) in 7,223 of 7,230 player-rounds over a 41-demo corpus (the remaining 7 are player_hurt events the GOTV recording dropped)
    • ADR computed from HealthDamageTaken will be ~1% higher than HLTV's on affected demos. Use HealthDamage (the raw dmg_health) to reproduce HLTV numbers
  • PlayerHurt.Player.Health() reports the HP before the event (the event is dispatched before the entity update is applied) by @akiver in #675
  • PlayerFlashed victims are paired with their flashbang by detonation rather than in FIFO order by @markus-wa in #663
  • BombExplode is no longer dispatched when the server shuts down a planted bomb without detonating it (e.g. a few ticks after a round is decided at half-time, overtime start or map end) by @markus-wa in #701 — the event now keys off CPlantedC4.m_bHasExploded, matching the native bomb_exploded count exactly in all 41 corpus demos (previously 17 spurious explosions across 12 demos)
  • BombDropped.EntityID is now the C4's entity ID on both the synthesized and the game-event path (it was the dropping player's entity ID, or 0 with mimicking disabled); the player's ID is still at BombDropped.Player.EntityID by @markus-wa in #737
  • Equipment.AmmoInMagazine() returns one more than before by @markus-wa in #718 — the m_iClip1 +1 offset was subtracted twice on CS2 demos, so every magazine read one round low and an empty one underflowed to 4294967295. Drop any +1 you added downstream. Also on the v5 branch (#719)
  • Grenade events carry the actual projectile: GrenadeEvent.Grenade is the projectile's WeaponInstance instead of a "last grenade of that type the player threw" guess, and InfernoStart is dispatched at the end of the frame the inferno was created in, see "New Features" (#708)
  • Deterministic ordering by @markus-wa in #739 and #663 — Player.Weapons(), GameState.Hostages() and Participants.SpottersOf() / SpottedBy() are sorted by entity ID, grenade / inferno UniqueIDs are deterministic, and leftover projectiles / infernos at round_officially_ended are destroyed in ascending entity-ID order (not throw order). 12 of 49 demos produced a different event order from run to run before
  • Examples are a separate Go module (examples/go.mod) by @markus-wa in #717 — the heatmap / draw2d / vdf dependencies no longer end up in your go.sum; cd examples before go run ./print-events -demo …
  • The v6 protos can coexist with v4's and v5's by @markus-wa in #748 — a program importing both v4 and v6 used to panic at init (extension number 61000 is already registered on message google.protobuf.MessageOptions). This is what lets CS Demo Analyzer parse CS:GO demos with v4 and CS2 demos with v6 (#749)
    • Proto full names in package msg use the package com.github.markus_wa.demoinfocs_golang.v6 and files are registered as v6/*.proto, e.g. com.github.markus_wa.demoinfocs_golang.v6.CSVCMsg_ServerInfo in v6/netmessages.proto. This affects protoregistry lookups, anypb type URLs and logged descriptor names
    • The generated file descriptor variables are renamed: File_<x>_proto → File_v6_<x>_proto (17 of them; message types like msg.CSVCMsg_ServerInfo keep their names)
    • Valve's custom option extensions (E_CodegenDeltaEncoder, E_MaximumSizeBytes, … 20 in total) are removed. demoinfocs never read them, they were only descriptor metadata
    • Go types, fields, the wire format and protojson field names are unchanged, so code that only uses the message types isn't affected
  • events.UserCmd.Command must not be modified by @markus-wa in #756 — the dispatched command is the decoder's baseline for the player's next delta (it is no longer deep-copied, see "Performance"). Use proto.Clone() to get a copy that can be modified. (events.UserCmd is new in v6, so this only affects alpha users)

New Features

  • Full user-command decoding for CS2 by @WangChuDi in #669
    • new events.UserCmd with the fully reconstructed command (buttons, mouse deltas, view angles, movement, subtick moves, input history, …), incl. delta-encoded commands
    • new option.UserCmdParsing modes: option.UserCmdParsingFull, option.UserCmdParsingButtonsOnly (default, low overhead) & option.UserCmdParsingDisabled
    • Decode the user commands of players whose first live commands are deltas by @l0rem in #753 (#751) — every DEM_FullPacket carries a full command per player, which now seeds the decoder of a player that has no command yet, instead of rejecting every delta with WarnTypeUserCommandBaselineMissing until the live stream sends a full command (in one demo, two players had no decoded commands for ~2.4 min)
      • on 41 CS2 demos: 58.2M → 69.5M UserCmd events (+19%), WarnTypeUserCommandBaselineMissing 11.27M → 123. 15 demos were affected (recent HLTV demos), in the worst one only 26% of the commands were decoded before
      • applies to UserCmdParsingButtonsOnly (the default) too, so you'll see more PlayerButtonsStateUpdate events on affected demos. Seeds are never dispatched themselves and never replace a live baseline; every command dispatched before is still dispatched unchanged
  • Decrypt encrypted net-messages in CS2 demos (chat messages in Valve matchmaking demos are encrypted since the Sept 2026 CS2 update) by @blinkzz in #696 and @akiver in #697, ported to v6 in #699. Also on the v5 branch
    • new option.NetMessageDecryptionKey(key) — set it to the key from the match730_*.dem.info file, which MatchInfoDecryptionKey() extracts for you
    • new ParserWarn types WarnTypeMissingNetMessageDecryptionKey (encrypted message seen, no key configured) & WarnTypeCantReadEncryptedNetMessage
    • CSVCMsg_EncryptedData is also exposed as a regular net-message for RegisterNetMessageHandler
    • Empty, truncated or corrupt payloads (e.g. a wrong key) give a WarnTypeCantReadEncryptedNetMessage warning instead of aborting the parse by @markus-wa in #705. The path is covered by unit tests with ICE-encrypted fixtures; there is still no real encrypted demo in the test suite, so reports are welcome
  • Track individual grenades: GrenadeEvent.Projectile by @markus-wa in #708 (#361, #601)
    • HeExplode, FlashExplode, SmokeStart / SmokeExpired, DecoyStart / DecoyExpired, FireGrenadeStart / FireGrenadeExpired and InfernoStart / InfernoExpired carry the *GrenadeProjectile, resolved from the event's entity ID, so Projectile.UniqueID() identifies one throw
    • Grenade is the projectile's WeaponInstance instead of a "last grenade of that type the player threw" guess (was wrong for 578 of 8,313 flashes and 512 of 4,107 smoke expiries in a 50-demo corpus), Thrower is filled from the projectile for CS2's thrower-less inferno_* events
    • Infernos are linked to their molotov / incendiary projectile (all inferno events in the corpus, GOTV and POV). InfernoStart is now dispatched at the end of the frame the inferno was created in
  • Player.Velocity() by @akiver in #674, and it works on demos recorded before AnimGraph 2 (protocol < 14089, where m_vecVelocity isn't networked on GOTV) by @markus-wa in #709 — derived from position deltas in snapshot server-ticks (v4 had a similar fallback, but under-reported by ~3× on demos with 3 ticks per snapshot and spiked on round restarts)
    • Tracking starts lazily on the first Velocity() call per player (one WarnTypeVelocityTrackingStartedLazily per parse); option.EagerVelocityTracking(true) tracks everyone from creation. No cost on demos where the velocity is networked
    • The POV recording player's networked value is used as-is; during an entity snapshot the velocity between the last two snapshots is returned so moving shooters don't read 0 at WeaponFire
  • Knife detail: common.KnifeType with MapKnifeType(), user-extensible KnifeTypes / KnifeTypeIndexMapping / KnifeTypeNames maps, and Equipment.OriginalString carrying the raw weapon string from game events by @markus-wa in #683
  • New events & getters by @markus-wa in #663:
    • events.InfernoFireOut — dispatched when an inferno's flames actually burn out (~5–7s), as opposed to InfernoExpired on entity destroy (~20s)
    • events.VoteCast with library-resolved player
    • BombDefuseStart.Site and PlayerJump.Position
    • Parser.FrameCount() — returns -1 until the total frame count is known
  • New sendtables.Entity API: OnUpdateFinished(func()), InPVS(), OnLeavePVS(func()), OnEnterPVS(func()), Replaced() (destroyed because its index was reused without a delete, e.g. on round restarts / backup restores) and String(), see "Breaking Changes" for the semantics
  • events.BombsiteUnknown (the misspelled BomsiteUnknown stays as a deprecated alias) in #717
  • Updated proto messages by @akiver in #660 and in #699 (svc_EncryptedData, CSVCMsg_VoiceData.caster, textallchat, CS_UM_*_CSGOLegacy renames, CCSUsrMsg_CustomHudClicked)

Fixes

  • OOM FIX: fail fast on corrupt bitstreams instead of OOM-killing — production demos that previously OOM'd at ~121 GB live heap (desynced entity state after a handler panic) now abort in ~2s at ~150 MB with a recoverable error:
  • Proper support for polymorphic fields in the CS2 sendtables parser by @Copilot in #654 — sub-fields of polymorphic pointers (e.g. m_pGameRules.m_pGameModeRules.* deathmatch fields) now resolve per active type, with deterministic handler rebuilds and nested-table enumeration in Properties()
  • Fix entity-stream desync (panic: "unable to find existing entity") on demos containing plugin-spawned entities such as CBeam — the quantized-float decoder now rounds to nearest, matching the engine's encoder by @akiver in #672
  • Fix entity index reuse without a delete (#601) by @markus-wa in #712 — the server sometimes creates a new entity (new serial) at the index of one it never deleted, e.g. on round restarts or backup restores. The old entity was overwritten without OnDestroy, so bindWeapon reused the stale *Equipment (and its ID) for the new weapon: 2,239 weapon entities sharing an *Equipment across 23 of 49 demos → 0, 158 spurious ItemRefunds across 14 demos gone, and a USP-S no longer shows up as a P2000. Stale projectiles / infernos that lingered in GameState() for 10k+ ticks are destroyed too
  • Fix grenade attribution by @markus-wa in #712 and #738
    • the thrown-grenade bookkeeping removes the grenade that actually went off instead of the last one of its type (6 PlayerHurt.Weapons corrected over 74 demos, tracked-but-never-detonated grenades at demo end 183 → 74)
    • GrenadeProjectile.WeaponInstance is taken from the weapon entity's own throw state (m_bPinPulled / m_fThrowTime), which fixes the wrong instance when a player throws a grenade on the same tick they pick up a floor grenade of the same type
  • Fix nil Entity/Owner on WeaponInstance of thrown grenades (GrenadeProjectileThrow, mimicked WeaponFire; #580) by @markus-wa in #688 — CS2 destroys the weapon entity before the projectile is created, so the last-known weapon of that type is used as a fallback (nil Entity went from 9–42% of throws per demo to 0)
  • Bomb event fixes by @markus-wa in #737
    • Bomb().Carrier & BombPickup for a C4 that is created before its owner's pawn (demos starting in freeze time): Bomb().Position() returned (0,0,0) for up to 6s and a drop by the first holder dispatched no BombDropped
    • no duplicate BombPickup on repeated owner updates (36 across 49 demos), no BombDropped for a pass to an owner that hasn't resolved yet
    • with option.DisableMimicSource1Events(true), BombDropped.EntityID / Player and BombPickup.Player are read from CS2's entindex / userid_pawn keys (they were always 0 / the GOTV bot)
  • Fix GameRules.RoundTime() always returning ErrFailedToRetrieveGameRule on CS2 demos (it still looked up the CS:GO property name) by @markus-wa in #726. Also on the v5 branch (#727)
  • Fix user command warnings never reaching event handlers by @l0rem in #752 (#751) — WarnTypeUserCommandDeltaDecodeFailed, WarnTypeUserCommandBaselineMissing and WarnTypeUserCommandBaselineMismatch went to the net-message dispatcher, so RegisterEventHandler(func(events.ParserWarn)) never saw them
  • Fix PlayerButtonsStateUpdate not working since the last CS2 update & resolve usercmd players via controller entity by @WangChuDi in #669
  • Fix float decoding differences between amd64 and arm64 (FMA contraction) by @akiver in #676
  • Fix Equipment.Silenced() panicking with a nil pointer dereference on equipment whose class has no m_bSilencerOn (defuse kit, kevlar, helmet, NVG) by @youdie006 in #695
  • Always update player user ID in getOrCreatePlayer by @akiver in #659
  • Broadcasts: fix player user-id mappings when starting parsing mid-match by @markus-wa in #655
  • Further correctness fixes by @markus-wa in #663:
    • Dispatch OtherDeath for CS2 entity_killed
    • Resolve PlayerHurt.Attacker via attacker_pawn fallback
    • Decode 32-bit QAngle components as noscale floats (fixes e.g. m_aimPunchAngle)
    • Stop GrenadeProjectile.Velocity() panicking on CS2 demos
    • Grenade type fallback by server class + ParserWarn instead of stderr for unknown models
  • Docs: typos by @antonkesy in #667, IsWalking() semantics in #684, game events / AmmoReserve() / FlashDuration corrections in #663, HealthDamageTaken's +1 depends on the server build in #707, stale API docs (ParseHeader(), NewCustomParser(), CS:GO references, ErrInvalidFileType message) in #717, new README "Error Handling" section in #730

Performance

  • v5.2.0 → v6.0.0-rc.0: ~42% less memory and ~13% fewer allocations on BenchmarkDemoInfoCs (s2.dem, benchstat, 10 interleaved rounds):

    v5.2.0 v6.0.0-rc.0
    memory (B/op) 350 MiB ± 1% 204 MiB ± 0% −42%
    allocs/op 5.79M ± 0% 5.06M ± 0% −13%

    Parse time is roughly the same as v5.2.0. Measurements so far are too noisy to say whether it is a few percent faster or slower; this is tracked in #757. Please report regressions you see on your own demos

    • fix alloc regressions, pool frame buffers & widen value caches by @markus-wa in #685
    • reduce parse hotspots (snappy destination reuse, field-path huffman peek table, less decoder boxing) by @markus-wa in #691
    • Participants().All() goes from 3 to 1 allocs/op in #739; frame buffers above 4 MiB are reused on POV demos (pov.dem peak RSS 211–220 → 171–178 MB) in #745
    • User OnUpdate property handlers cost ~9 ns more per call for the panic guard (BenchmarkUserPropertyHandlers +3.6%, worst case with a handler on every pawn property)
  • UserCmdParsingFull is ~15–25% faster by @markus-wa in #756 — decoded commands are stored as the next delta's baseline without a deep copy (6381816.dem: 18.8–19.9 → 13.5–15.7 s, fokus-vs-aurora-m1-cache.dem: 9.15–9.35 → 7.97–8.08 s; dispatched UserCmd events identical, see the breaking-change note on UserCmd.Command)

Changes

  • Dependencies: pkg/errors & x/exp replaced with the standard library in #716 (%w, errors.Is, cmp.Ordered); oklog/ulid dropped in #712; testify/objx dropped in #725; the example-only deps (draw2d, go-heatmap, freetype, x/image, vdf) moved to the examples module in #717; new ice-cipher-go v1.0.0 for net-message decryption (#699, #702); godispatch v1.5.1 (fixes handler order & dropped handlers when registering after the first Dispatch), gobitread v0.2.5, protobuf 1.36.12 (#666), testify 1.12.1 (#670), x/image & x/text (#658)
  • Repo: the default branch was renamed master → main in #721 (git branch -m master main && git fetch origin && git branch -u origin/main main && git remote set-head origin -a), the GitLab mirror is gone
  • CI: actions updated by @katsugtgz in #677; least-privilege workflow permissions in #690; OSV-Scanner dependency scanning in #689; test-csda disabled by @akiver in #694 and re-enabled against the v6 fork of CS Demo Analyzer in #703, #750 (CS:GO demos as a smoke test of CSDA's combined v4 + v6 build), #754 and #755; push / PR runs deduped in #720; coverage via codecov-action in #723; jobs parallelised & sharded in #744 and #747; a flaky trailing-newline reader test fixed in #682
  • Upgraded linter config by @akiver in #680
  • Protos: prepare-protos.py applies the package, import prefixes and option stripping before generate.sh, and the nightly "Update Protobufs" workflow uses it (#748)

New Contributors

Full Changelog: v5.2.0...v6.0.0-rc.0

Coming from an alpha? The incremental notes: alpha.0 · alpha.1 · alpha.2 (has an alpha.1 → alpha.2 migration table) · alpha.3. Since alpha.3: #753, #754, #755, #756.

Discussions / Chat / Announcements

Discord Chat

Don't miss a new demoinfocs-golang release

NewReleases is sending notifications on new releases.