Repository navigation
⚠ BREAKING CHANGES
- the
k4-worldtext:sharedapicapability now servesIK4WorldTextProviderinstead ofIK4WorldTextSharedAPI. A consumer built against 1.x fails atCapability.Get()withKeyNotFoundExceptiononce 2.0 is installed. Change the field toPluginCapability<IK4WorldTextProvider>and callForPlugin(this)on the result. - config persistence is gone. The
saveConfig,removeFromConfig, andmodifyConfigparameters were removed,RemoveAllTemporary()was replaced byRemoveAll(), and nothing is written to or read from disk. Re-create texts from your own map-start handling.
Features
- api: scope the shared API per consumer plugin.
IK4WorldTextProvider.ForPlugin(IPlugin owner)returns a scope keyed byModuleName; every text belongs to the plugin that created it, an id issued to another plugin is treated as unknown, foreign-id access is logged with the real owner's name, andRemoveAll()removes only the caller's texts. The same plugin gets the same scope after a hot reload, so it can clear texts left by its previous instance (0402eac) - api: remove the config persistence parameters from the shared API and rewrite the README around the shared-API-only model (aa197d3)
- api: document every public member of the shared API and ship
K4-WorldText-SharedAPI.xmlnext to the DLL, so the argument, threading, and clamping rules show up in IntelliSense (60cf26f)
Bug Fixes
- threading: marshal API entity work onto the game thread and make text tracking concurrent, so calls from a
Task.Runbody, anHttpClientcontinuation, or a database callback no longer touch entity memory off-thread (e51b65c) - threading: run the entity work inline when the caller is already on the game thread, so a text exists in the world by the time
AddWorldTextreturns, and capture the game thread id synchronously inLoadinstead of racing the first world update (001d67c) (e7cf60b) - api: validate arguments synchronously on the calling thread and throw
ArgumentExceptionbefore any work is queued, instead of failing later on the game thread with no way to report it (daaa8ad) - api: validate
CCSPlayerControllerand its pawn at the boundary and again inside the deferred spawn, so a player who disconnects between the call and the world update produces a logged warning instead of a crash (f12a002) - api: copy the caller's
Vector/QAngleat the boundary so a respawn never reads entity-backed memory, makingpawn.AbsOriginsafe to pass (8757296) - api: contain entity-work exceptions and throw
KeyNotFoundExceptionfor unknown text ids. A failed spawn rolls back, logs, keeps the id tracked, and retries on the next round start, rather than surfacing at the caller (d180290) - api: return
nullfromGetWorldTextLineEntitiesfor unknown ids and skip entities that are no longer valid, instead of handing back dangling pointers (5494db2) - api: log rejected shared-API calls before throwing, so a misbehaving consumer is identifiable from the server log (a690c50)
- entities: clamp
point_worldtextMessageTextto its 512-byte budget, truncating on a character boundary (8a1a998) - entities: clamp the numeric
TextLinestyling fields and truncateFontNameto the entity's 64-byte field before writing to native memory;NaNbecomes the in-range value closest to zero (ebc651c) - entities: dispose
WorldTextchildren on removal and guard the mutators after dispose, and untrack disposed texts so a disposedMultilineWorldTextis never re-used (af6014f) (f5abea6) - geometry: normalize yaw to
[-180,180)inEntityFaceToDirection(ec2c2be) - geometry: derive the floor line stacking direction from
absRotationinstead of the previous entity, so multi-line floor texts stack correctly (07a6f3f) - perf: update world text entities in place instead of respawning them when the line count, font sizes, and background layout are unchanged (38f215a)
- perf: teleport world text entities in place, respawning only when one of them is no longer valid (55afc76)
- perf: skip the round-start reapply for texts whose entities survived the round transition, and cache entity validity in that check (2e5b79d) (2a86740)
Code Refactoring
- mark the geometry and spawn helpers
internalso they are no longer part of the public surface (5392a19)
API Changes (1.3.0 -> 2.0.0)
Capability
k4-worldtext:sharedapi(name unchanged) now servesIK4WorldTextProviderinstead ofIK4WorldTextSharedAPI
New interface
IK4WorldTextProviderIK4WorldTextSharedAPI ForPlugin(IPlugin owner)- the scope for one consumer plugin, keyed byModuleName. ThrowsArgumentNullExceptionfor a null owner andArgumentExceptionfor an emptyModuleName. Safe to call from any thread
Removed parameters
saveConfigfrom bothAddWorldTextoverloads and bothAddWorldTextAtPlayeroverloadsremoveFromConfigfromRemoveWorldTextmodifyConfigfromTeleportWorldText
Renamed methods
RemoveAllTemporary()->RemoveAll(), now scoped to the calling plugin
Changed behaviour
- Ids are per scope.
UpdateWorldText,RemoveWorldText, andTeleportWorldTextthrowKeyNotFoundExceptionfor an id that is not tracked by the calling scope, including every id issued before the last map change;GetWorldTextLineEntitiesreturnsnullinstead - Bad arguments throw
ArgumentExceptionsynchronously on the calling thread before any entity work is queued GetWorldTextLineEntitiesis game thread only and throwsInvalidOperationExceptionelsewhere, because raw entity pointers cannot be marshalledtextLinesis copied at the call, so the caller may reuse or clear its list afterwardsTextLinenumeric fields are clamped, never rejected:FontSize1-500,ScaleandBackgroundScale0.01-10,BackgroundWorldToUV0.001-10,BackgroundBorderWidth/BackgroundBorderHeight0-1000, the depth offsets ±100,BackgroundMaxCharsPerLine1-256,BackgroundPadChars0-256,BackgroundWidthInflation0.1-10.FontNameis truncated to 64 UTF-8 bytes andTextto 512- Nothing is persisted to disk. Every text lives until its owner removes it or the map ends. Unloading or reloading the plugin destroys every text and resets the id counter, so ids restart from 1
Miscellaneous
- deps: remove the unused
Newtonsoft.Jsonpackage reference (c824519)
Full Changelog: v1.3.0...v2.0.0