-
Notifications
You must be signed in to change notification settings - Fork 56
xNVSE 6.1, 6.2, 6.3: What's New
xNVSE 6.1 is out and it brings a lot to the table for the people who script for Fallout New Vegas. The goal for this release was to improve the experience of the scripting system by adding in quality-of-life features, new functions and more. There have also been multiple bug fixes.
NVSE has it's own compiler different from the GECK's that's usually only activated in commands that support NVSE expressions. The NVSE compiler is a lot more flexible than the limited GECK compiler: it supports more operators, arrays and string variables natively. With xNVSE 6.1 it's also got a feature boost but we'll get to that later. A major pain point for scripters was that when passing arguments to functions you were required to first place the expression inside a variable before being able to pass it as an argument.
; compiles pre-xNVSE 6.1
let fTemp := Player.GetActorValue Health + 50
Player.SetActorValue Health fTemp
; doesn't compile pre-xNVSE 6.1
Player.SetActorValue Health (Player.GetActorValue Health + 50)
This has now been remedied by inline expressions, which allow you to emplace NVSE expressions inside parenthesis when passing arguments to functions. This also means you get all the benefits of the NVSE compiler while programming inside inline expressions, including array support and using string concatenation operator for example.
Player.SetName (arStringsFirstNames[iCurIdx] + " " + arStringsLastNames[iCurIdx])
Inline expressions have no performance cost and can in some cases even increase performance of your script.
Also known as anonymous user defined functions, lambdas are nameless user defined functions which are placed inline within a parent script. Lambdas are a part of the NVSE expression compiler and runtime.
; A lambda placed in a variable
ref rCallback
int iCount
let rCallback := (begin function {}
let iCount += 1
print "I have been called " + $iCount + " times."
end)
SetMainGameLoopCallback rCallback 1 1
; A lambda placed in an inline expression
SetMainGameLoopCallback (begin function {}
print "I have been called from an inline expression"
end) 1 1
Lambdas can be passed to any function that accepts a script as argument. They can access and modify all variables defined in the parent script.
If your lambda is only a single line long, and you optionally wish for the lambda to return the result of that line, this syntax can be used:
; UDF that takes a single parameter, and increments variable iCount by it
let rCallback := {iSomeParam} => iCount += iSomeParam
Call rCallback 10 ; increment iCount by 10
Call rCallback 5 ; increment iCount by 5
SetOnHitEventHandler ({} => this.Say Hit) 1 ; makes every actor scream when hit
CallWhile ({} => print "iCount is " + $iCount) ({} => (iCount += 1) < 1000) ; Prints the value of iCount each frame until iCount reaches 1000
Note: you will need to update Hot Reload to the latest version so that lambdas can be hot reloaded. On hot reload, any lambdas within the reloaded script will get invalidated so you need to reregister any event handlers which utilize lambdas, best way is by adding GetGameHotReloaded
(docs) after your GetGameLoaded
if-statement that registers your event handlers.
Before xNVSE 6.1, a dot could only be used on a local ref variable or a reference form. Now, inside NVSE expressions, you can use dot syntax on the result of functions, on ref variables from external quests or references and array elements.
eval MyQuestScript.rMyRefVar.FakeScriptEvent "OnClose" Player
eval GetSelf.SetActorValue 1000 ; GetSelf is a function that returns a reference - now valid!
let sName := GetName (aListOfRefs[100].GetBaseObject) ; array element must contain ref
NVSE expressions can now declare variables, without you needing to explicitly declare them on top.
Before:
int iCount
let iCount := 10
After:
let int iCount := 10
More Examples:
foreach array_var aIter <- aArr
; do stuff with aIter
loop
if eval ref rRef := GetCrosshairRef && IsReference rRef
; do something with rRef
endif
- CallAfterSeconds seconds:float udf:script - calls UDF after argument amount of seconds have elapsed in-game
- CallForSeconds seconds:float udf:script - calls UDF each frame until argument amount of seconds have elapsed in-game
- CallWhile udf:script condition:script - calls UDF each frame while condition script returns true
- Ar_DumpF array:array_var file path:string - Dumps the contents of an array to the specified file.
CallAfterSeconds 5.5 ({} => print "5.5 seconds later...") ; calls UDF after 5.5 seconds
CallForSeconds 10 ({} => print "la la la") ; calls UDF each frame for 10 seconds
CallWhile ({} => ivar += 1) ({} => ivar < 1000) ; calls left UDF each frame until value of ivar reaches 1000
- Fix console print applying formatting on escaped % character
- Fix ar_erase on numeric maps
- New operators in NVSE expressions: |=, &=, %= (thanks Demorome)
- Fix multithreading issues by making static buffers thread_local
- Add short hand macro for
let
:-
iCount = 10
->let iCount := 10
-
iCount += 10
->let iCount += 10
- etc.
-
- You can now define multiline expressions and strings using parenthesis
Hopefully these new features will be of good use. Any bug reports can be issued in the issues section or on the xNVSE Discord server.
-- Kormákur (korri123), xNVSE lead developer
- Fix string concatenation bug (broke sprint animations)
- Fix comments making line numbers in compiler errors inaccurate in GECK
- Fix vanilla commands failing if the
ParamInfo*
wasnullptr
- Increase maximum args for plugins calling UDF scripts from 5 to 10
- Add Expression Evaluator to Plugin API
- Fix shorthand assignment bugs
- Fix minor lambda issues
- Revert script crashing functionality change as it broke old broken (yet still used for some reason) mods
- Scripting: allow = to be used in place of := in more contexts for consistency with shorthand assignment macro
- Fix save bloat issue (NVSE string and array types not getting cleaned up for UDF parameters) introduced in last version
- Add support for lambda scripts to capture variables from parent script if the lifetime of the parent script is shorter than the lambda (UDFs and effect scripts) in select functions (CallFor, CallAfter and CallWhile).
- EDITOR: Fix variable assignment macro syntax being bugged when prefixed with a variable type (int iVar = 10 would not work for example before)
- Additions to PluginAPI: IsScriptLambda, LambdaSaveVariableList and LambdaUnsaveVariableList (latter two are used to capture variables)
- New scripting functions/commands
- Introduce script decompiler for mod scripts which sources are lost
- Decompiler can be used to verify that scripts compiled correctly as GECK can sometimes mess up the compilation
- It can also be used to find out which script lines caused errors in mods.
- Add to PluginAPI
- HasScriptCommand
- DecompileScript
- Fix lambda issue with error messages
- Fix assignment shorthand syntax for math inside array brackets
- Bug fixes
- Fix lambda crash
- Fix some decompiler issues
- Fix Vanilla UI+ / Stewie's Tweaks bug with bContainerDefaultToRightSide
- Fix hot reload lambda issue
- Add commands ar_Generate, ar_Init (thanks Demorome)
- Optimize string var assignments from let expressions to be much faster in scripts
- Capture lambda variables inside SetEventHandler in temporary scripts (UDFs and effect scripts)
- Add inline expression support in console, allow string_var and array_var in console (ported from Improved Console plugin)
- Only issue script error warnings in top corner if GECK is installed (for mod authors) or
[Release] bWarnScriptErrors
INI option is set to 1 - Print decompiled lines for vanilla game script errors if
bWarnScriptErrors
is 1 - Prevent Dispel from spamming script error log when it returns false to stop script
- Add multiline comment support in scripts (/* this is a comment */)
- Remove hardcoded 4 MB co-save limit
- Introduce warning if mods are deemed to be leaking, display which mods and instructions on how to clean the co-save.
- bWarnScriptErrors
- Fix decompiled line being wrong
- Only enable by default if GECK was opened in the past 2 days
- GECK Editor
- Fix variable assign macro being case sensitive to variable types
- Ar_Filter, Ar_MapTo, Ar_Generate, Ar_FindWhere
- Allow no SetFunctionValue if return value is 0
- Fix co-save issues with 6.1.8
- Show vanilla script errors only for mods you have edited scripts for in the past.
- Fix public ref maps not getting loaded from cosave.
- General bug fixes
- Fix lambda issues
- Add support for loops, lambdas and macros in console
- Add ar_Any, ar_All, ar_DeepEquals, GetWeaponRegenRate, SetWeaponRegenRate script functions
- Add support for int a, b, c variable declaration syntax
- Fix if blocks being validated inside multiline comments
- Allow == to compare arrays without just comparing IDs
- PluginAPI: add GetContainerType
- Ar_Generate improvements
- Fix another subtle lambda issue - thanks Eddoursul for bug report
- Fix possible crash while loading save
- Fix crash if GetWeaponType is called on non-weapon
- Bug fixes
- Fix lambda scripts in console scripts / jip_script_runner esp-less script bugs
- Fix CallAfterSeconds not being cleared on game load
- Add commands Ar_Unique, CallFunctionCond (thanks Demorome!)
- Fix PluginAPI CallFunctionScripts not returning array function values
- Add PluginAPI::ArrayAPI::ArrayHasKey to Plugin API
- New script command: CallWhen
- Fix Sv_Destruct causing crashes for captured lambda variable lists
- Fix ar_Unique not working
- Allow lambdas to continue gracefully even if parent variable list can't be resolved
- Address possible performance issue in handle event, where Structured Event Handling was being used more than necessary
- Fix inline expressions not being implicitly assigned a "this" reference
- Fix animation group param type not accepting strings in inline expressions in-game
- Fix nested call to CallWhen (CallWhen scripts calling CallWhen) causing a game crash
- GECK: Fix issue in variable assign macro where using a tab instead of a space would make it fail to detect the macro
- GECK: Fix compilation of lambdas inside Result Scripts (before they would not get properly cleaned up inside GECK and you would end up with new Script forms inside the master each compilation)
- GECK: Fix return value of UDFs being automatically assigned as number, instead of being ambiguous which would cause incorrect compile time errors
- GECK: Fix "expected end of line" error in some cases where inline expressions were used within NVSE expressions
- GECK: Fix nested one line lambdas not compiling correctly (i.e.
{} => call ({} => print "I'm nested")
)
- Fix lambda bug which resulted in console errors and possibly memory leaks and crash
- Fix inline expression and variable definition bugs
- Fix GetPlayerCurrentAmmo, GetAmmoCasing, GetDebugSelection, GetWeaponItemMod, GetWeaponCritEffect, GetHotkeyItem not having return types for NVSE expression compilation
- Make ForEach loops work with Form lists
- Fix
GetPackageCount
printing 0, betterGetNthPackage
prints - Fix memory leak in Algohol functions
- Added command ModUIFloat
- Add missing FOSE functions GetNthQuestObjective, GetQuestObjectiveCount, GetCurrentObjective, PrintActiveTile, SetCurrentQuest
- Fix short circuit bug
- Fix GetRefs 201 not retrieving NV-unique items
- Disable error logging on RemoveMe when it returns from scripts
- Fix CallAfterSeconds when SGTM is not 1.0
- Add "check for dupes" option to "listAdd.." funcs
- GECK: Fix line numbers when compiling lambda scripts and multiline comments
- GECK: Fix assignment shorthand quirks and crashes regarding string maps
- Bug fixes
- Fix invalid memory happening in Ar_InsertRange
- Fix dodgy code causing crashes with InventoryRefs
- Fix refs not working correctly in
&&
NVSE expressions - Fix PreLoadGameHook to run reliably and load cosave vars correctly
- Fix issue with string function results in expression evaluator
- Fix string and array vars leaking when copied to a lambda
- Update project to Visual Studio 2022
- Add new script event framework for plugins
- Add commands
- SetEditorID
- sv_Trim
- Enhance commands
- TempCloneForm
- Add option to set mod index of cloned form to caller script
- CallAfterSeconds, CallForSeconds, CallWhile, CallWhen
- Add option to pass parameters by value
- Add bRunInMenuMode argument
- TempCloneForm
- PluginAPI
- Add NVSEEventInterface
- Allow plugins to create custom events and dispatch them in an easy way
- Allow plugins to register event handlers
- Robust filtering mechanism for param types and calling reference
- Export ScriptTokenCanConvertTo
- Add ExtractArgsV to plugin expression evaluator for easier variadic arg extraction of args
- Add NVSEScriptInterface::CompileScript
- Add NVSEScriptInterface::CompileExpression
- Query all plugins first before loading them
- Add NVSEEventInterface
- Bug fixes
- Fix issue with ar_Erase
- Fix issues with event handling system
- Fix possible crashes in JIP script runner scripts and lambdas
-
Add commands
- DispatchEventAlt, SetEventHandlerAlt, GetSelfAlt, DumpEventHandlers, GetEventHandlers, CallWhilePerSeconds, CallAfterFrames, GetSoldItemInvRef.
-
Enhance commands
- Add MaxAngle filter arg to GetRefs__ functions.
- Added DontRunInMenuMode / DontRunInGameMode flags for CallWhile / CallWhen
- Remove the limit on the event name length for Set/RemoveEventHandler functions.
-
Bug fixes
- Fix SetActorBaseFlagsLow - was using the baseForm's flags instead of the actor's flags.
- Fix GetNthQuestObjective and GetCurrentObjective (credits to c6)
- Fixed TestExpr not returning 0 (false) if an NVSE error occured in one of its nested child expressions.
- Fixed ProcessEventHandler not restoring the removed ":" character from the eventName string if the event isn't an LN event.
- Fixed an issue with SetEventHandler + LN events (introduced in last version) - the event filters were being type-validated before determining if the event was an LN event (LN events don't have types to check).
- Fixed OnSell event - it should now actually run.
-
PluginAPI
- Fixed, clarified and added functions for event handler NVSE plugin exports.
- Expose ReportError for PluginExpressionEvaluator.
-
For NVSE plugin devs
- Allow multiple unit test files
- Fix max script size compilation limit at runtime. Credits to Korma. However, nothing except developer tools use this at the moment, and JIP's Script Runner was already limited by a fixed-size character buffer.
-
nvse_config.ini
- nvse_config.ini now ships with all relevant settings, along with descriptions.
- Add bAlwaysPrintScriptCompilationError in [Release]. Off by default. Only affects in-game script compilation error messages, i.e using JIP's Script Runner or other. (By default, it only printed the errors if console was already open)
-
Enhance commands
- SetEventHandler(Alt) & RemoveEventHandler: added a way to define handlers with a specific priority, so they can run before/after other handlers: added a "priority"::SomeInt arg. More information here.
- NumToHex: Added alias IntToHex, added AddPrefix optional arg.
- ToNumber now has a third arg, bReportError. If toggled, it will report an error if converting the string to a number was unsuccessful. The error can be caught using TestExpr.
- RunScript now returns a boolean value instead of always printing if the script returned true or false.
-
Add commands
- IntToBin, ValidateRegex, IsEventHandlerFirst, IsEventHandlerLast, GetHigherPriorityEventHandlers, GetLowerPriorityEventHandlers
-
Bug fixes
- SetEventHandlerAlt can no longer be used with LN events, to prevent confusion. LN events are purely owned by LN, so arrays can't really be used, and the flush-on-load wouldn't happen.
- Fix flushing script callbacks (Call__ functions) right after the "NewGame" event finishes running.
- Fix not pushing event name for new event calling system, fixing GetCurrentEventName for newer events.
-
PluginAPI
- Add ReportErrorIfNoResultGiven event flag; if off (default) and a handler does not return a result, will pass an array element with the Invalid type.
- Allow HasScriptCommand to detect script blocks (thanks, yvile!).
- Add SetNativeHandlerFunctionValue
- Add Ptr-type event params
- Add Set/RemoveNativeEventHandlerWithPriority
-
nvse_config.ini
- Document
bAlwaysPrintScriptCompilationError
option.
- Document
-
Enhance commands
- Added a DontRunWhilePaused flag/option for all condition "Call" functions.
-
Add commands
- IsInventoryRef, HasAmmoEquipped, GetEquippedWeaponCanUseAmmo, IsEquippedAmmoInList, GetEquippedWeaponUsesAmmoList, DebugPrintVar
-
Bug fixes
- Fix let macro not supporting array assignment
- Fix UDFs not allowing short/long param types.
- Fix let macro not supporting short/long var declarations. REQUIRES RECOMPILE; scripts that were using this had the macro evaluate wrongly, which is baked into the script.
- Fix preprocessor not being used in runtime CompileScript, plus fix crash there when trying to use the multiple-variable-declarations-on-one-line macro.
- Fixed quest script variables declared using One-Line Multiple Variable Declarations not being accessible for other scripts.
- Fixed type lookup for quest script variables not ignoring commented-out variables.
- Fixed runtime compilation error for certain scripts with lambdas in them, caused by preprocessor being turned on at runtime now.
- Fixed GECK sometimes not recognizing variable types for variables declared inside UDF parameters.
-
PluginAPI
- Fixed the plugin logging interface, which required an API change. Don't think any plugin was using this yet though.
-
nvse_config.ini
- Document
sPluginLogPath
string option in the LOGGING section.
- Document
-
Enhance commands
- Add "useSingleDelimiterString" arg to sv_Split
-
Add commands
- GetHeadingAngleX, GetWeaponCanUseAmmo, SetAmmoConsumedPercent
-
Bug fixes
- Fixed compilation bugs w/ parentheses in strings
- Fixed ForEach loops breaking early when looping over 1-element formlists (resulting in nothing happening)
- Fixed runtime script issues with functions returning ambiguously-typed values
- Use new StrHash function from Jazzisparis to fix rare cases of string hash collision.
- Fixed flags that got broken for CallFor, CallAfter, and CallAfterFrames
- Add locale support for string functions (credits to yvile)
- Fixed assigning a number to a ref var in eval contexts never working
- Fixed SetStringIniSetting, deprecated the broken SetStringGameSettingEx
-
General enhancements
- Added a more detailed warning for trying to use unpatched EGS version (ty Wall).
-
Add commands
- DisablePlayerControlsAlt / DisablePlayerControlsAltEx
- EnablePlayerControlsAlt / EnablePlayerControlsAltEx
- GetPlayerControlsDisabledAlt / GetPlayerControlsDisabledAltEx
-
Bug fixes
- Reverted fix "Fixed assigning a number to a ref var in eval contexts never working". Caused more trouble than it was worth.
- Fix PickOneOf's return type
-
Add commands
- CopyIRAlt, CompileScript
-
Enhance commands
- DecompileScript - can now decompile result scripts for any applicable form type (Jazzisparis)
- Add aliases for DisableControlsAlt(Ex)
-
Bug fixes
- Fixed disabling attacking with DisableControlsAltEx also disabling NPC attacks
- Fixed sv_Split's new arg, JoinDelimiters, which previously garbage strings sometimes
- Fixed CallAfterFrames callbacks not being cleared on load
- Fixed EGS check repeatedly telling to install the Epic Games Patcher even if the patcher was already installed.
-
General enhancements
- RegisterCommand - will print both the command name and its alias (if any) (Jazziparis)
-
Enhance commands
- Demorome: GetRefs-style functions have a new optional filter arg to filter by baseForm.
- Demorome: All scripts in "nvse/user_defined_functions" folder are now precompiled at startup; this means CompileScript will just return an already compiled script, reducing lag if it would've otherwise been compiling in a busy segment.
-
Bug Fixes
- Kormakur: fixed memory leak when calling lambdas with variables inside of console/scriptrunner.
- Potentially fixed refIDs for 0xFF lambdas and CompileScript scripts from rarely getting changed to point to some other form when loading (credits to lStewieAl).
- Demorome: fixed CompileScript caring about lower/upper case and "" vs "/" in filepaths for caching.
- Jazzisparis: ScriptAnalyzer::Decompile - Fixed local vars definitions missing in result/partial scripts; Fixed invalid opcode not being shown.
-
Enhance commands
- Demorome: Added flags to prevent sleeping, waiting, or fast-travelling to DisablePlayerControlsAltEx.
-
Bug Fixes
- Demorome: Fixed ar_FindWhere not working if the return value is an array.
- Demorome: Fixed UDF text files in "user_defined_functions" folder never getting cached with CompileScript if installed via MO2
- lStewieAl: Fixed missing actor and baseProcess checks in HasAmmoEquipped
- Kormakur: Fix rare UB in ExpressionEvaluator::Evaluate when script line fails
-
Add commands
- GetDoorSound, Ar_GetNth
-
Add events
- OnApplyIMOD, OnRemoveIMOD, OnLockBroken, OnLockpickSuccess, OnLockpickBroken, OnUnlock, OnTerminalHacked, OnTerminalHackFailed, OnRepair, OnEnable, OnDisable
-
Enhance commands
- Kormakur: Fixed a use after free issue in vanilla ResetQuest command
-
General improvements
- WallSoGB: Plugin preloading + increased max heap sizes
- Default heap sized increased to 500MB from 400
- File heap increased to 72MB from 64
- Demorome: Added kMessage_ScriptPrecompile for plugin developers to hijack the script compilation process
- Added unary bitwise not operator (~)
- WallSoGB: Plugin preloading + increased max heap sizes
-
Bug Fixes
- Demorome: Delay OnSell hook to avoid NVAC conflict
- Demorome: Clear inventory reference cache on preload + improved thread safety
- Confused: Added VERY EXPERIMENTAL new script compiler, which will be temporarily unsupported
- Confused: Cleaned up various hooks / improved consistency between runtime compilation and GECK compilation
- Confused: Fix / cleaned up decompiler output for scripts that utilize lambdas
- Demorome: Fixed eval assignment operators not flooring integers
- Demorome: Fixed some runtime compilation error messages
- Confused: Fixed parsing inconsistency with NVSE expression parser commands
- Bug Fixes
- Confused: Fixed crashes related to OnUnlock events. They are temporarily disabled pending some cleanup.
- Bug Fixes
- Confused: Fix some macros not parsing correctly when spaces were ommitted. Ex:
int i=10
- Confused: Fix some macros not parsing correctly when spaces were ommitted. Ex:
- Bug Fixes
- Confused/Kormakur: Fix a crash related to quest event list use-after-free
- Bug Fixes
- Confused: Fix SRM command resolution
- Confused: Add experimental FireChallenge command