Orvid / Caprica

A compiler for the Papyrus scripting language used by the Creation Engine.
MIT License
84 stars 15 forks source link

Unresolved function name #30

Open Elscrux opened 11 months ago

Elscrux commented 11 months ago

Hi, I have some issues compiling a Skyrim script as it doesn't detect some function names. Here is an example to reproduce. Thank you for this project. Looks very cool!

My script:

Scriptname Test extends Actor

Function Test()
    GetActorBase()
EndFunction

Calling Caprica


.\Caprica.exe Test.psc -g skyrim -i "D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source" -f "D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source\TESV_Papyrus_Flags.flg"
Adding current working directory to import list: D:\Steam\steamapps\common\Skyrim Special Edition\Papyrus Compiler\Input
Adding import directory: D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source
Importing files...
Imported 13938 files.
Adding file 'Test.psc' to namespace ''.
Compiling Test.psc
Test.psc (4, 2:14): Fatal Error: Unresolved function name 'GetActorBase'!```
ForsakenShell commented 11 months ago

Disregard this response, I was in error.

Elscrux commented 11 months ago

Huh, using your script code didn't work either, failing with the very same error.

.\Caprica.exe Test.psc -g skyrim -i "D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source" -f "D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source\TESV_Papyrus_Flags.flg"
Adding current working directory to import list: D:\Steam\steamapps\common\Skyrim Special Edition\Papyrus Compiler\InputAdding import directory: D:\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source
Importing files...
Imported 13938 files.
Adding file 'Test.psc' to namespace ''.
Compiling Test.psc
Test.psc (4, 27:39): Fatal Error: Unresolved function name 'GetActorBase'!

Also, I'm not quite sure why this script wouldn't work? The Skyrim compiler compiles this just fine. Calling on self or parent is not required, nor is saving the result of a function call to a variable.

ForsakenShell commented 11 months ago

Ahh, looking at the Actor.psc I see there is no GetActorBase() function for Starfield - I assumed you knew what function you wanted, it actually exists and, you were simply having a syntax issue.

Be sure to decompile the games scripts and reference those directly (those which are "Native") ie, ScriptName Actor Extends ObjectReference Native hidden

Also be sure to use your editors "search across files" function eg, search for 'ActorBase' to find all it's uses; specifically native functions that return one.

The function you'll be looking for is GetLeveledActorBase() in Actor.psc

The alternate method is actorRef.GetBaseObject() as ActorBase

Always be sure to sanity check your inputs and outputs - never trust anything or anyone - especially yourself and your own code

Edit:

Also, I'm not quite sure why this script wouldn't work? The Skyrim compiler compiles this just fine. Calling on self or parent is not required, nor is saving the result of a function call to a variable.

True, self is implied (the compiler sticks it in behind your back). And the compiler should autogenerate a hidden variable to store the result. But it's bad practice to do both of those things as it leads to code smell. Just because your car lets you drive into a brick wall doesn't mean you should do it. ;)

Elscrux commented 11 months ago

I'm not actually looking to compile for Starfield, just for Skyrim. GetActorBase() does exist for Skyrim and the script header for Skyrim is the following:

Scriptname Actor extends ObjectReference Hidden

All Skyrim scripts have official source files packed with the CK. And GetActorBase() definitely exists. Like I said, the Skyrim compiler provided by Bethesda can compile this without any problems.

The alternate method is actorRef.GetBaseObject() as ActorBase

I mean yeah, calling GetBaseObject() (a function on ObjectReference) works because apparently mostly function names from scripts that extend another script aren't recognized. Because of that, trying a function like EvaluatePackage() also doesn't compile when used.

True, self is implied (the compiler sticks it in behind your back). And the compiler should autogenerate a hidden variable to store the result. But it's bad practice to do both of those things as it leads to code smell. Just because your car lets you drive into a brick wall doesn't mean you should do it. ;)

Sure, I agree. I wouldn't use this code for anything I would actually do with payprus. I just wanted to provide a minimal example of my error so I just everything else.

ForsakenShell commented 11 months ago

Sorry to muddy the issue, I've been fighting with Caprica for Starfield and my brain automatically read "Starfield" when on closer inspection you are, indeed, talking about "Skyrim Special Edition".

I've found the VM sometimes generates errors if you don't give it an explicit variable to return a result to when compiling with Caprica in some circumstances. eg, actiRef.Activate( npcRef ) vs bool b = actiRef.Activate( npcRef ) This has cause me to be a bit wordier than strictly necessary using Caprica for some code segments but doesn't seem to be your issue.

As far as class inheritance goes, I haven't found that to be an issue myself. But I am not using Caprica for an older title - tbh, not sure why you are when there is the "proper" compiler available but that isn't really relevant here.

I do question your paths, the typical (default Bethesda) setup is to have the vanilla script sources in \Data\Scripts\Source\Base\ and the user script sources in \Data\Scripts\Source\User\. You are pointing the import path to \Data\Scripts\Source.

fwiw, I compiled targeting FO4 and SF (I don't even have any version of SK installed) and these are the results I got from the following script example:

Scriptname Test extends Actor

Function Test()
    GetLeveledActorBase()
EndFunction

Native FO4 Compiler (through the CK): No errors, file compiled

Caprica v0.3.0 (FO4, command line): No errors, file compiled caprica.exe -g "fallout4" -f "F:\Fallout 4\Data\Scripts\Source\Base\Institute_Papyrus_Flags.flg" -i "F:\Fallout 4\Data\Scripts\Base" -o "F:\Fallout 4\Data\Scripts" "F:\Fallout 4\Data\Scripts\Source\User\Test.psc"

Adding current working directory to import list: F:\Fallout 4\Data\Scripts\Source\User
Adding import directory: F:\Fallout 4\Data\Scripts\Base
Importing files...
Imported 12541 files.
Adding file 'Test.psc' to namespace ''.
Compiling Test.psc`

Caprica v0.3.0 (SF, command line): No errors, file compiled caprica.exe -g "starfield" -i "F:\Starfield\Data\Scripts\Base" -o "F:\Starfield\Data\Scripts" "F:\Starfield\Data\Scripts\Source\User\Test.psc"

Adding current working directory to import list: F:\Starfield\Data\Scripts\Source\User
Adding import directory: F:\Starfield\Data\Scripts\Base
No flags specified, Using default Starfield flags file.
Importing files...
Imported 4594 files.
Adding file 'Test.psc' to namespace ''.
Compiling Test.psc

Even if I bungle the import path to Data\Scripts\Source then it still compiles correctly for me (targeting either FO4 or SF).

This issue must be exclusive to targeting Skyrim [Special Edition] or your command line or your game setup.

Elscrux commented 11 months ago

The path Scripts\Source instead of Source\Scripts is simply a result of old conventions that I use. You can use any path there and this is where I store my script sources, so this shouldn't be an issue from what I can see :) Thanks for trying to help me out though!

ForsakenShell commented 11 months ago

Yes, all my actual mods script sources are on a completely different drive and the compilers are happy with that as long as you point to them correctly.

Your inheritance issue is an odd one though - did something overwrite the Actor.psc by chance and remove the function definition? Just grasping at straws but you never know?

Elscrux commented 11 months ago

No, I made sure that Actor.psc is exactly the version that is delivered with the CK, and was also able to replicate a similar issue when calling other scripts in the past. At this point, I think the issue is either me using Caprica incorrectly (using the command from my initial post) or some issue with Caprica itself as the compiler by Bethesda which I am trying to replace (with a faster and open-source alternative) has exactly the same inputs as Caprica does.

ForsakenShell commented 11 months ago

fwiw, I wouldn't use "an open source alternative" simply because it's open source. I choose my tools based on correctness of output. I was always suspicious of Caprica's output and with my problems with SF scripting I am even more so suspicious of it.

In my case it's a script constant which I update with every version: Int iCurrentVersion = 7 Const When updated to: Int iCurrentVersion = 8 Const It always returns 0, if I set it to 6 it works fine. If I set it to 128 it return 10??? All of the following changes returns 0 too: Int Property iCurrentVersion = 8 AutoReadOnly Hidden

Int Property iCurrentVersion Hidden
    Int Function Get()
        Return 8
    EndFunction
EndProperty

However, this works:

Int Property iCurrentVersion Hidden
    Int Function Get()
        Return ( 12 / 3 ) * 2
    EndFunction
EndProperty

When I try to decompile the script with Champilion I get errors about instruction nodes and it won't output anything.

Again, completely unrelated to your issue other than I don't trust Caprica as of late.

Elscrux commented 11 months ago

That's a good point and very weird behavior! Maybe make a separate issue for your findings :) I value it being open-source here because I was noticing some edge case troubles with the Bethesda compiler. Otherwise, I wouldn't have searched for an alternative either. Being faster would also a be nice side bonus.

ForsakenShell commented 11 months ago

I value it being open-source here because I was noticing some edge case troubles with the Bethesda compiler.

That's a fair response.

Being faster would also a be nice side bonus.

The compiler can take a week for all I care - what is important is the speed (and correctness) of the code it's producing. ;)