Running changelog
Running changelog
This is the bleeding-edge changelog since version 2025.04, which is still in the pre-release phase. See the 2025.04 page for the upcoming release.
Caveats
- unit shaders receive TRS transforms instead of matrices, breaking shaders. See the “Smooth script piece animations” section below.
 - non-turreted units now rotate themselves to face the target if needed. See below for details.
 - removed 
^123style texture referencing for unit def icons forgl.Textureand similar interfaces. There is a new set of icon-related callouts, see below. - removed Python bindings for AI. Apparently unmaintained and unused.
 - removed 
UpdateWeaponVectorsMT,UpdateBoundingVolumeMT, andAnimationMTspringsettings. These were just in case, but MT seems safe enough after some time live testing. - removed 
/AdvModelShadingcommand and theAdvUnitShadingspringsetting, the adv mode is now always on. In practice there wasn’t any difference since GLSL became mandatory. - removed 
gl.UnitGL4,gl.FeatureGL4,gl.FeatureShapeGL4, andgl.UnitShapeGL4. These did not do anything. - handicap (native income multiplier) no longer applies to reclaim. Use 
gadget:Allow{Unit,Feature}BuildStepto replace, if desired. Backwards compatibility feature check:Engine.FeatureSupport.noHandicapForReclaim. /group add Nno longer selects the entire group, just adds./groupN(without space) unaffected. Feature support tag:Engine.FeatureSupport.groupAddDoesntSelect.- immobile units that 
canKamikazeno longer disregard theblockingunit def tag. BeamLaserandLightningCannontype weapons now pass their actual projectileID to callins rather than-1.BeamLaserandLightningCannonnow obey ellipsoid and/or cylinder target volumes correctly, this will result in a slightly different effective range volume.- in-line text color codes: 0x11 and 0x12 (decimal 17 and 18) now work as color code indicators, in addition to 255 and 254 respectively.
Engine.textColorCodesstill only lists the old ones. - default value for 
LogRepeatLimitspringsetting 10 → 0, see below. - area resurrect command now puts a leash on repair sub-commands (behaviour change, but also the repair subcommands now have 5 args instead of 1).
 - widgets can now sign up to receive the 
widget:Explosioncallin. There are some arcane visibility rules that boil down to it revealing much more info than the existingwidget:ShockFrontcallin. - removed the 10 mutator limit, can now have arbitrarily many (this may affect lobbies, autohosts etc who may have assumed the limit).
 - rmlUI textures use nearest pixel filtering instead of linear. The intended effect is crisper text with anti-aliasing.
 Spring.SetProjectileTargetnow errors on invalid args instead of silently ignoring.- fully removed support for 32-bit builds.
 
Deprecation notice
wupget:DrawUnit,DrawFeature,DrawShieldandDrawMaterialare deprecated. Nothing changes in behaviour, but they are (and have been for a long time) a bad idea to use as a performance anti-pattern. Use shaders as a replacement.- deprecated 
Spring.GetUnitCommands(unitID, 0) → number commandCount, useSpring.GetUnitCommandCount(unitID). The non-0 overloads still return a table of commands and are not affected. - similarly deprecated 
Spring.GetFactoryCommands(unitID, 0), use the newSpring.GetFactoryCommandCount. - deprecated 
Spring.GetCommandQueue, useSpring.GetUnitCommands(which has always been 100% equivalent), except for the case above. - deprecated the 
ghostedBuildingsengineoption. You can read it manually as a modoption and set every unitdef not to leave ghosts. 
Features
Non-turreted units rotate towards target
A set of changes aimed to help develop melee units.
- units with non-turreted weapons will try to face the target, if all other weapons fail to pass targeting checks. This happens both within the unit’s range (frequently) and outside of it (less frequently).
 - angle fire tolerance checks won’t apply in case the aimpoint is clipped inside the target (doesn’t happen in all cases, so the tolerance is still something to be aware of of for CQB weapons / units).
 - non-turreted non-front oriented weapons won’t be handled correctly by the change above for now.
 - there could be unknown side effects. It’s a test change.
 
Icon atlases
gl.Textureand alike no longer supports referencing icon textures via^123(unit def ID).- icons atlas can now be specified right from 
gamedata/icontypes.lua(FIXME how?). This way the atlas is not built but loaded. Spring.AddUnitIconcan now operate with sub coordinates in case of atlased input texture (args 6-9 are now u0, v0, u1, v1 respectively).- add 
$iconsaka$icons0, and$icons1textures. They respectively represent the initial icons atlas as seen during the game load and a possible atlas that is created for some of the icons got replaced. - add 
Spring.GetUnitIconData,Spring.GetIconData,Spring.GetAllIconDatato mostly get the atlas coordinates. See the API listing for details, the exact interface is still subject to change. 
Camera callins
- added 
wupget:CameraRotationChanged(rotX, rotY, rotZ) → nil. - added 
wupget:CameraPositionChanged(posX, posY, posZ) → nil. 
Chat via widgets
- added 
Spring.SendPublicChat(msg) → nil, for sending a chat message. Equivalent to/say. - added 
Spring.SendAllyChat, andSpring.SendSpectatorChat, same interface as above, for sending chat to allies/spectators. Equivalent to using/saywith the “a:” or “s:” magic destination prefixes. - added 
Spring.SendPrivateChat(msg, playerID) → nil, for sending a private message (aka whisper) to a specific playerID. Almost equivalent to/wbynum, but does not support the magic 255 destination. 
GL debugging
- added 
DebugGLReportGroupsboolean springsetting, default true. Shows OpenGL push/pop groups in GL debug. - the 
/debugGLoption now takes an optional numerical argument, 0-15. 0 and 1 control the whole debug view without touching anything else (i.e. work as before). Otherwise values 2-15 are treated as a bitmask: 8 controls stacktraces, 4 report groups, 2 the whole debug enabled/disabled state, 1 ignored. 
New Website
- Slashscreen, in an effort to procrastinate from university finals, completely redid the website.
 - Reworked the Api docs.
 - New guides.
 - Documented RmlUi bindings.
 
CEG rendering
- adds the following tags to 
CBitmapMuzzleFlametype CEG particles:particleSpeed,particleSpeedSpread,airdrag,gravity. These work the same as they already do forCSimpleParticleSystemtype particles. - added 
animParams1andanimParams2to CEGs, similar to weapons. Texture 1 is used forCSimpleParticleSystemand the “front” texture ofCBitmapMuzzleFlame, texture 2 is used for the “side” texture of muzzle flame. Other CEG classes don’t support this yet. NumberlessanimParamsused as a fallback. - added 
drawSideXanddrawSizeYbool tags toCBitmapMuzzleFlame, allows to skip some of the two “forward” sprites. X is the one parallel to the ground when shooting horizontally. There is nodrawSideZbecause you can just set that texture to empty. 
Infotex commands
- added 
/showLoS. - added 
/showInfoTex foo, wherefoois one of the existing info textures (e.g./showInfoTex elevationis equivalent to/showElevation). - all the 
/showFoocommands can now accept 0/1, in addition to argument-less toggling. 
Smooth script piece animations
- unit shaders receive TRS transforms instead of matrices, breaking shaders. This will require gamedevs to update GL4 shaders that used to employ the engine provided transformation matrices SSBO.
 - the new format is not directly documented anywhere, but you can look at basecontent shaders.
 - added 
Engine.FeatureSupport.transformsInGL4backwards compatibility check. 
Base64
- added 
Encodingglobal table (likeSpringormathetc), available everywhere. So far contains base64 encoding, more (such as JSON) to be added lated. - added 
Encoding.EncodeBase64(string plain, bool? stripPadding = true) → string encoded. Can optionally remove the extra=at the end. - added 
Encoding.DecodeBase64(string encoded) → string plain, decodes a base64 string (if there’s an invalid character, it parses just the valid prefix). - added 
Encoding.IsValidBase64(string) → bool. - added 
EncodeBase64Url,DecodeBase64Url, andIsValidBase64UrltoEncoding. Same as above, except uses the base64url character set. 
Duplicate logs
- the 
LogRepeatLimitspringsetting, which controls how many duplicate logs in a row can end up in the infolog, can now accept 0 for infinite. - default value for 
LogRepeatLimit: 10 → 0 - native ingame console no longer filters duplicates (max 1 in a row → infinite)
 
GLTF/GLB model format support
.gltfand.glbmodel formats are now supported.- GLTF parser will insert a few empty pieces as root / sub-root.
 - materials, textures and vertex colors embedded in the GLTF itself are not supported. Mostly because GLTF expects PBR workflow, which the standard engine shader doesn’t do.
 - GLTF can use a Lua metadata file similar to Assimp, custom model attributes in GLTF can also be used to provide the same data. Supports the existing tags: 
tex1,tex2,midpos,mins,maxs,height,radius,fliptextures,invertteamcolor. - add a new 
s3ocompatbool attribute, both for GLTF and Assimp models. Enables the same right handed - left handed flip of the model as it’s done in s3o. This is experimental and probably very bugged. If your model is converted from s3o and animates incorrectly, give this option a try. - does not support re-parenting or the baked rotation angles. Use your 3d editor to change them instead. Assimp not affected.
 
Ghosts
- add 
leavesGhostunit def tag. Controls whether the unit leaves a ghost. Defaults to true for buildings (maintains previous behaviour). - add 
leavesGhostUnitDefs entry, same. - add 
Spring.GetUnitLeavesGhost(unitID) → bool. - add 
Spring.SetUnitLeavesGhost(unitID, bool leavesGhost, bool? existingGhostRemains = false). IfleavesGhostbecomes false and the unit already had a ghost, whether the existing ghost is removed or sticks around is controlled by the second arg. - note that the 
ghostedBuildingsengineoption still exists and makes all of the above interfaces no-op, but is scheduled for removal. 
Text coloring
- added 
AllowColorFontsbool springsetting, defaults to false. Allows fonts to be colored instead of monochromatic. In practice this means emojis render as expected, though a fancy enough font could also do something to normal text. - in-line text color codes: 0x11 and 0x12 (decimal 17 and 18) now work as color code indicators, in addition to 0xFF and 0xFE (decimal 255 and 254) respectively. The significance of this is that 255/254 are normal, printable characters from reasonable languages so treating them as color codes can ruin otherwise normal text by eating characters and setting random colors.
 Engine.textColorCodesstill only lists the old ones.- added 
TextDisableOldColorIndicatorsbool springsetting, defaults to false. If true, the previous 255 and 254 color codes stop working andEngine.textColorCodeslists the new ones. 
Explosion event in unsynced
- add 
Script.SetWatchExplosion(weaponDefID, bool), and the corresponding Get, to unsynced. - widgets can now receive the 
Explosioncallin, same arguments as the gadget one but can’t use the return value to block the CEG. There are some arcane visibility rules (that include the visibility of the explosion’s CEG) that boil down to it revealing a bit more info than the existingwidget:ShockFrontcallin which used to fulfil a similar role. 
Team unit limits
- add 
Spring.TransferTeamMaxUnits(fromTeam, toTeam, amount) -> bool success, transfers max unit limit across teams. - add 4th optional boolean arg to 
Spring.TransferUnit(unitID, teamID, bool? given, bool? transferLimit), default false. If true, also adjusts both teams’ unit limit by 1, making it possible for the transfer to work even if both teams are at limit. 
Death metal
- add 
Spring.CreateUnitWreck(unitID, int? wreckLevel = 1, bool? emitSmoke = true) → featureID?. Creates a wreck as if the unit died. - add 
Spring.CreateFeatureWreck(featureID, int? wreckLevel = 1, bool? emitSmoke = false) → featureID?. Creates a wreck as if the unit died. - add 
Spring.AddFeatureDamagewith the same signature asSpring.AddUnitDamage. Note that one of the args is paralyze time, but features don’t take paralyze damage. - add a new 
checkDeathbool arg toSpring.SetFeatureHealth(featureID, health, bool? checkDeath = false). It was discovered that the current behaviour is that features set to negative health don’t die from HP removal and it takes an instance of damage to “poke” them into death. The default offalsepreserves this, set it totrueto let features die immediately from HP removal. - add 
Spring.SetFeatureFireTime(featureID, fireTime), sets a feature “on fire” (similar to being damaged with afirestartertagged weapon) with that much time to live, in seconds. Set to 0 to cancel. - add 
Spring.SetFeatureSmokeTime(featureID, smokeTime), makes the feature emit smoke (similar to freshly killed wrecks) for that many seconds. Note that smoke size is proportional to time remaining. - add the corresponding getters (
Spring.GetFeatureFireTime,Spring.GetFeatureSmokeTime) for the above. 
Pre-game phase control
- add 
system.useStartPositionSelecterbool modrule. If false, engine won’t eat clicks on startbox during the placement phase. - add synced 
Spring.SetTeamStartPosition(teamID, x, y, z) -> bool ok. - add synced 
Spring.SetPlayerReadyState(playerID, bool ready) -> bool ok. - add unsynced 
Spring.RequestStartPosition(x, y, z, bool? ready) -> nil, sends a request to start at given position. Equivalent to the native picker. 
Misc
- add a dimensionless Scale operator to unit scripts. No ancillaries such as WaitForScale though.
 - add 
Spring.GetPieceProjectileName(pieceProjectileID) -> string name. Returns the name of the source piece for a piece projectile (“body”, “turret” etc). Nil for non-piece projectiles. - add 
Spring.GetAllProjectiles(bool excludeWeaponProjs = false, bool excludeWeaponProjs = false) -> { proID, proID, ...}. - removed the 10 mutator limit, can now have arbitrarily many.
 - add 
accurateLeadingnumerical unit weapon tag (note, not weaponDef). Controls how many extra accuracy iterations are done when calculating shots. 0: current behaviour (single iteration, fails to hit at large speed disparities and/or weird angles). 1: one extra iteration, enough to get a perfect solution for non-ballistic shots and usually good enough for non-extreme ballistic shots too. 2+: extra iterations for ballistic shots, if needed. In practice, shouldn’t need to go higher than low single-digit values. Note that the calculation always stops when 1-frame resolution accuracy is achieved (since unit and projectile movement are all frame-discrete), so setting this arbitrarily high should still be safe and reasonably performant. - math extras (
math.hypot,math.normalize, bit ops etc) now available in LuaParser envs (modrules, defs parsing, etc). - added 
Spring.GetFactoryCommandCount(unitID) → numberchecks the queue length in a factory’s build queue (note thatGetUnitCommandCountis for the rally queue in factories). - add 
ThreadPinPolicyspringsetting to control which CPUs to use. (0) = Off; (1) = System Default; (2) = Exclusive Performance Core; (3) = Share Performance Cores. - added new CEG impact filters, 
shieldandintercepted. BeamLaserandLightningCannontype weapons now pass their actual projectileID to callins rather than-1.BeamLaserandLightningCannonnow obey ellipsoid and/or cylinder target volumes correctly.- immobile units that 
canKamikazeno longer disregard theblockingunit def tag. - add ‘system.nativeExcessSharing’ modrule, controls whether the resource sharing level (aka “red slider”) applies. Note that this also prevents excess from flowing back to the allyteam. If you want excess to flow to allies and only block changing the share level, use the existing 
gadget:AllowResourceLevel. - add 
Game.nativeExcessResourceto read back the above. - add 
MiniMapDrawPingsboolean springsetting, defaults to true. Whether engine renders pulsating white squares on the minimap when a label is placed. - if a factory “changes” a build order into a build order of the same type (e.g. by using command insert) it no longer resets build progress.
 /group add Nno longer selects the entire group, just adds./groupN(without space) unaffected. Feature support tag:Engine.FeatureSupport.groupAddDoesntSelect.- expose the rmlUI data model backing table as 
__GetTable(). - add 
gl.GetEngineModelUniformDataSize(number index) → number sizeInElements, number sizeInBytesOnCPUto grab the size of the model uniforms buffer on the CPU side. - add 
LuaVBO:CopyTo(otherVBO, sizeInBytes) → bool okto copy the GPU side content from the current LuaVBO to another. - add a second bool arg and an optional second return value to 
Spring.GetGroundDecalTextures(bool? mainTex, bool? alsoFilenames = false) → string[] textures, string[]? filenames. - add 
mouse2tomouse10“keys” for mousebuttons that can be bound, dittosc_mouse2-10scancodes. LMB (mouse1/sc_mouse1) is planned to be made bindable later. - rmlUI textures use nearest pixel filtering instead of linear. The intended effect is crisper text with anti-aliasing.
 - added 
DWMFlushnumerical springsetting, for Windows only. Forces Windows Desktop Compositors DWMFlush before each SDL_GL_SwapWindow, preventing dropped frames (use nVidias FrameView to validate dropped frames, or BARs Jitter Timer widget). Value of 1 does DWMFlush before SwapBuffers, value of 2 does DWMFlush after swapbuffers. - enabling dev mode (either via startscript or at runtime) adds 
debug.*functions to synced Lua. /smoothmeshrenderer stays enabled even if you disable cheats.- trying to set a deprecated/nonexistent springsetting via Lua now produces a warning.
 /givenow gives a correct hint for @x,y,z usage.Spring.GetTeamList(allyTeamID?)no longer crashes if it receives 2+ args (but still ignores them, you can’t get the combined team list of multiple allyteams).- added 
GL.TEXTURE_2D_ARRAYLua constant. Spring.SetProjectileTargetnow errors on invalid args.
Fixes
- fix the “no sound when removing bluetooth headphones” issue.
 - fix texture overrides for tex1 and tex2 for GLTF models not being read from 
*.gltf.luametafile. - maybe fixed a rare bug of using an incorrect parser for model assets.
 - fix incorrect number of CPUs being detected on Linux with offline CPUs.
 - fix a crash when more than 2048 unit defs exist.
 - fix units who expected to path entirely within an exit-only zone but exited it getting confused.
 - probably fix an icons rendering related crash.
 - fix 
Spring.GetMapStartPositionsreturning teamIDs offset by 1. - fixed crashing aircraft sometimes bouncing off the ground without dying.
 - disabling cheats no longer disables debug airmesh view.
 - fix RmlUi crash when reloading stylesheets with documents containing scripts in head section.
 - fix some graphical interfaces producing harmless warnings/errors on headless builds.
 - fix some RmlUI crashes.
 - fix some remaining performance issues with fonts.
 - fix some pathing/QTPFS issues.
 - fix some jitter on Windows in mostly-idle and/or low speed multiplayer games.
 - fix some issues with models rendering at world origin before game start.