View plansUnlimited access, team features, and more
ChatGPT o4-mini-high
Share
![]()
PLUS
You said:
The attached files are papyrus scripts for use in moding skyrim. They interface with a SKSE plugin. However the apear to have a reference Printscreen.checkpath which is invalid can you determine what the propper reference shouuld be and if there are any other obnious errord
ChatGPT said:
Thought for 21 seconds
In Papyrus every script‐ and function‐name is case‑sensitive, and you must import exactly the same name that your SKSE plugin registered. From what you describe, your scripts are calling:
papyrus
CopyEdit
Printscreen.checkpath(...)
but your plugin almost certainly registered a function called CheckPath in a script whose name is capitalized differently — for example:
-
Script name:
PrintScreen(with a capital “S”) -
Function name:
CheckPath(camel‑case)
So your call should look like:
papyrus
CopyEdit
Import PrintScreen ; … later … Bool ok = PrintScreen.CheckPath(someString)
(or, if your plugin’s script really is named Printscreen, then Import Printscreen and Printscreen.CheckPath(...) — but always with Capital P in “Path” and matching the exact script name).
Other things to look for
-
Import statement
Make sure at the very top of your.pscyou have:papyrus
CopyEdit
Import PrintScreen ; ← exact script name -
Function declarations must match
If your SKSE plugin exposedcpp
CopyEdit
bool CheckPath(StaticFunctionTag, string path)then in Papyrus you should have no wrapper function of your own; you just call the static:
papyrus
CopyEdit
Bool canWrite = PrintScreen.CheckPath(pathToCheck) -
Semicolons & End-function markers
Papyrus requires every statement to end with a semicolon, and every function to be closed:papyrus
CopyEdit
Function MyFunc() ; … EndFunction -
Script/file name alignment
The filename (PrintScreen.psc) must match the script name inside. If you’ve renamed the file, open it and verify:papyrus
CopyEdit
ScriptName PrintScreen ; ← this must match what you import -
Auto on properties
AnyPropertydefinition you intend to have autogenerated getters/setters should includeAuto:papyrus
CopyEdit
String Property BasePath Auto
If after renaming your import and call to exactly match your plugin’s generated .psc you still see errors, please paste the header of your Papyrus script (the ScriptName line, Import lines, and the call site) so we can verify the exact casing and signatures.
You said:
given the plugin code in pligin.cpp can you see what is not matchin in the registrations? I also note the I get errors stating the PrinScreen is undefined. I assume it needs to be imported smewhere but I don't kn ow which script of import it into. Please advise
ChatGPT said:
Thought for 10 seconds
The two things that are tripping you up are:
-
Case‑sensitive name mismatches
-
Latent vs. non‑latent flag swapped in your
RegisterFunctioncalls
1. Matching the Papyrus script name and function names
In your C++ you have:
cpp
CopyEdit
vm->RegisterFunction("CheckPath", "PrintScreen", CheckPath, true); vm->RegisterFunction("TakeScreenshot","PrintScreen", TakeScreenshot, false);
That means Papyrus is looking for a script called exactly PrintScreen (capital “P” and “S”), with two static functions:
papyrus
CopyEdit
String function CheckPath (String filePath) Bool function TakeScreenshot(String basePath, String imageType, Float compression, String ddsCompressionType) latent
Your Papyrus needs to:
-
Live in a file named
PrintScreen.psc -
Begin with:
papyrus
CopyEdit
ScriptName PrintScreen -
Any other script that calls into it must have at its top:
papyrus
CopyEdit
Import PrintScreen -
And when you call the functions, you must match casing exactly:
papyrus
CopyEdit
; synchronous path check String result = PrintScreen.CheckPath("C:\MyScreenshots\") ; latent screenshot (will fire PrintScreenComplete when done) Bool ok = PrintScreen.TakeScreenshot("C:\MyScreenshots\", "png", 0.85, "none")
If you’re currently calling Printscreen.checkpath (lower‑case “s” or “c”), or your script is named Printscreen.psc or Printscreen inside, Papyrus simply won’t find it.
2. Swapping your latent flags
The fourth argument to RegisterFunction(...) is whether the function is latent (i.e. returns immediately and completes later via callback). You have:
-
CheckPath→true -
TakeScreenshot→false
But CheckPath is a synchronous directory‑validation, while TakeScreenshot is your multi‑step latent. You need:
cpp
CopyEdit
papyrus->Register([](RE::BSScript::IVirtualMachine* vm) { // non‑latent vm->RegisterFunction("CheckPath", "PrintScreen", CheckPath, false); // latent vm->RegisterFunction("TakeScreenshot", "PrintScreen", TakeScreenshot, true); SKSE::log::info("Papyrus functions registered successfully"); return true; });
Checklist to get rid of “PrintScreen undefined” errors
-
File name:
PrintScreen.psc -
Script header:
papyrus
CopyEdit
ScriptName PrintScreen -
Other scripts that call it must include:
papyrus
CopyEdit
Import PrintScreen -
Calls must match exact casing:
papyrus
CopyEdit
; not Printscreen.checkpath! String msg = PrintScreen.CheckPath(pathToTest) Bool ok = PrintScreen.TakeScreenshot(path, type, quality, ddsType)
Once you’ve got the casing consistent and swapped that latent flag, Papyrus will be able to find and bind both of your functions.
You said:
OK my formuls are defined in printscreenNS and PrintSCreen_formula_Script so I am thinking It would be better to changge the plugin.cpp registration to ,atch either the printScreenNS or Printscreen_formula_Script. Am Icorrent in this
ChatGPT said:
Thought for a few seconds
You’re absolutely on the right track: the second parameter of RegisterFunction(…, scriptName, …) must exactly match the ScriptName declared in your .psc file. If your formulas live in two separate scripts—
-
PrintscreenNS.psc (with
ScriptName PrintscreenNS) -
PrintScreen_formula_Script.psc (with
ScriptName PrintScreen_formula_Script)
—you have two basic options:
1. Register under each of those script names
Simply call RegisterFunction once for each script you want to expose a given native function to. For example, if you want CheckPath available in both scripts:
cpp
CopyEdit
papyrus->Register([](RE::BSScript::IVirtualMachine* vm) { // non‑latent path checker in both scripts: vm->RegisterFunction("CheckPath", "PrintscreenNS", CheckPath, false); vm->RegisterFunction("CheckPath", "PrintScreen_formula_Script", CheckPath, false); // latent screenshot only in PrintScreen_formula_Script, for example: vm->RegisterFunction("TakeScreenshot","PrintScreen_formula_Script", TakeScreenshot, true); return true; });
That way, Papyrus scripts named either “PrintscreenNS” or “PrintScreen_formula_Script” can do:
papyrus
CopyEdit
Import PrintscreenNS String ok = PrintscreenNS.CheckPath(thePath) Import PrintScreen_formula_Script Bool done = PrintScreen_formula_Script.TakeScreenshot(basePath, type, quality, ddsType)
2. Rename your Papyrus script(s) to a single shared name
If it makes organizational sense, you can unify everything under one script, say PrintScreen. Then:
-
Change the top of both
.pscfiles to:papyrus
CopyEdit
ScriptName PrintScreen -
Alter any other script that imported the old names to do:
papyrus
CopyEdit
Import PrintScreen -
In
plugin.cpp, register once:cpp
CopyEdit
vm->RegisterFunction("CheckPath", "PrintScreen", CheckPath, false); vm->RegisterFunction("TakeScreenshot","PrintScreen", TakeScreenshot, true);
Key point
Whatever you choose, the second argument to RegisterFunction must exactly (case‑sensitively) match the ScriptName in your .psc. If Papyrus is still complaining “undefined,” double‑check:
-
The
.psc’s filename matches (e.g.PrintscreenNS.pscforScriptName PrintscreenNS). -
The case of every letter in the script name.
-
That you’ve recompiled and placed the updated
.pexin yourData/Scripts/folder before testing in‑game.
Once the names line up, your native functions will bind correctly and the “undefined” errors will vanish.
You said:
ok so check path is called by Printscreen_mainQuest and PrintScreen_MCM while takePhoto is only called by the Printscreen_mainquest. At present there is no Printscreen script and I don't want to create one. I propose to register Printscreen_Fornula since I think it contains both functions. is this possible? Am confused about the necessity for both PrintscreenNS and Printscreen_Formula. They appear to be quite convluted. I only need a checkpath function and a takephoto function. It looks like these files needlessly generate wrapper functions. I would like to simplify the code if possible
ChatGPT said:
Thought for 24 seconds
You absolutely can point both native calls at your existing Printscreen_Formula_Script—but there are two things you must get exactly right:
-
The script‐name string in your C++ registration must match the
ScriptNamein your.psc -
The “latent” flag (fourth argument) must reflect whether the call is synchronous or not
1. Update your plugin.cpp registrations
Right now you have (via ):
cpp
CopyEdit
vm->RegisterFunction("CheckPath", "PrintScreen", CheckPath, true); vm->RegisterFunction("TakeScreenshot", "PrintScreen", TakeScreenshot, false);
To instead target your Printscreen_Formula_Script (assuming your Papyrus file begins with ScriptName Printscreen_Formula_Script), change it to:
cpp
CopyEdit
papyrus->Register([](RE::BSScript::IVirtualMachine* vm) { // non‑latent directory check vm->RegisterFunction("CheckPath", "Printscreen_Formula_Script", CheckPath, false); // latent snapshot capture vm->RegisterFunction("TakeScreenshot", "Printscreen_Formula_Script", TakeScreenshot, true); SKSE::log::info("Papyrus functions registered under Printscreen_Formula_Script"); return true; });
-
Script name
"Printscreen_Formula_Script"must exactly match the name declared in your.psc(case‑sensitive). -
CheckPathis non‑latent (→false) because it returns immediately. -
TakeScreenshotis latent (→true) because it does its work over multiple frames.
2. Adjust your Papyrus imports and calls
In every Papyrus script that invokes these functions (e.g. Printscreen_mainQuest and PrintScreen_MCM), replace any old import/call with:
papyrus
CopyEdit
Import Printscreen_Formula_Script ; Synchronous path check String result = Printscreen_Formula_Script.CheckPath(myPath) ; Latent screenshot Bool ok = Printscreen_Formula_Script.TakeScreenshot(basePath, fileType, compression, ddsType)
3. Simplify your wrapper scripts
-
Drop the separate
PrintscreenNSwrapper entirely if it only forwarded arguments toPrintscreen_Formula_Script. -
Consolidate any remaining Papyrus wrapper functions into one script (
Printscreen_Formula_Script) that declares the native signatures:papyrus
CopyEdit
ScriptName Printscreen_Formula_Script Function CheckPath(String path) Global Native EndFunction Function TakeScreenshot(String basePath, String imageType, Float compression, String ddsCompressionType) Global Native Latent EndFunctionThen your game’s other scripts just import and call these natives directly, with no extra stubs.
Why this works
-
SKSE’s
RegisterFunction(…, scriptName, …)makes your C++ routines appear as static methods on the named Papyrus script. -
Papyrus will only bind them if the script name and function name exactly match.
-
By consolidating to a single
Printscreen_Formula_Script, you avoid juggling multiple wrappers—and you only need to maintain one import in your quest/MCM scripts.
Once you’ve rebuilt and dropped the updated .pex into Data/Scripts/, reload Skyrim, and your calls to Printscreen_Formula_Script.CheckPath and .TakeScreenshot will resolve cleanly.
Sources
Tools
ChatGPT can make mistakes. Check important info.