Jump to content

Skyrim modding help: Quest script unexpected behavior and huge papyrus log

Recommended Posts

Sorry for epic topic name but I cant say it more short :)

So I was making a mod and was testing it on a nonclean save and all was OK, I did it for a reason - I could not fix thing I am about now so I moved to old good save to spend time developing and testing game mechanics, but now I am finishing it and it comes to this.

There are two problems:

First one - it kinda runs immediatly as I start game(because of Debug.notification I put into OnUpdate) at first I thought that Quest that supposed to be launched on a script event somehow launched so I broke all ways of it by commenting stuff or adding return - does not helped. That wasnt happening before and I dont know why.

Its also have all its aliases empty, even those that not relied on SM Event Data. I figured out that quest is not running _  isRunning() == false isStopped() == true isStarting()==false  _and it is a script that is alive for some reason. None of that were happening on dirty save.
Funny thing thou - its parent quest script was working too, but I forgot to set is as Start Game Enabled.
Also it creates alot of text in Papyrus log, to which I get in a second.

I kinda minimized this stuff by first adding condition into OnInit event on quest that returns if quest "isStopped", it reduced log size a little but not much. Second I added another state which scripts locks on to if condition is met, there I declered another oninit.

So now it works, but poops int log alot and can produce lagspikes. Fact that script does well all I wanted it to do makes me little more happy but it is still something weird and a problem. Interesting thing is that most of errors in logs happen before quest is launched, but this mess not accompanied by lagspikes. Lagspikes begin to manifest when I kill about 12-15 NPCs from quest and can go away if I run around and return to battle and pile of corpses. But I was testing while have opened editor and browser (they take alot of RAM).


Second one is a continuation of first: in Papyrus Log it says that functions are called on none:

[12/10/2019 - 07:17:31PM] Error: Cannot call reinforcement() on a None object, aborting function call
    [ccccWETESTWEWEWEWEW (14014C0D)].ccccwescript.placereinforcements() - "ccccWEScript.psc" Line 273
    [alias ImperialScout1 on quest ccccWETESTWEWEWEWEW (14014C0D)].ccccwealiasscript.OnUpdate() - "ccccwealiasscript.psc" Line 154


Also warnings many warnings:

[12/10/2019 - 07:21:34PM] warning: Assigning None to a non-object variable named "::temp22"
    [ccccWETESTWEWEWEWEW (14014C0D)].ccccwescript.placereinforcements() - "ccccWEScript.psc" Line 273
    [alias reinforcement1000 on quest ccccWETESTWEWEWEWEW (14014C0D)].ccccwealiasscript.OnUpdate() - "ccccwealiasscript.psc" Line 154


The thing is - now I made it work good on clean save but it is creating huge Papyrus Log and now I think it is freezing VM sometimes - because of lag spikes somtimes and because it clearly displayed in the log.


Mod basically makes some NPCs to stalk player and they have some helping scripts(which manage packages and unstuck them) and one of them is "leader" also has registered for LOS Event for player and can drop tail of markers (which are activator and can be moved and recycled). At beginning I was used modified Wildernes Encounters scripts but the now its almost nothing from them left here. So there is no complicated stuff, but still too many lines of code.

It is made like Wildernes Enconter same principles but also optional aliases which can be recycled, corpses are stored into array and cleaned all at once after some time when quest stops. Non-optional aliases scripts unregister for updates and anything as they die. Optional are doing same, but can be brought back by function call. What can cause problem?

That function placereinforcements() returns int for debug purposes and has no arguments.  Here is part of its code. Line 273 is one where I read 'reinforcement' property on ccccwealasscript. It is bool property that distinguishes recycling alias from nonrecycling. Isfree() is a bool function that checks whether is is not in use. Arrays are all of 32 size, and there is 12 aliases.

int inam = 0
int freereinforcementid = 200
if reinforcementsnum >= reinforcementsmax
return 210 ; reinforcements are at max

inam = 0
    while inam < refaliasarray.length ;searching for alias for new bandit ;;;reinforcement
        if (refaliasarray[inam] as ccccwealiasscript).reinforcement == true
            if (refaliasarray[inam] as ccccwealiasscript).isFree()
                freereinforcementid = inam
inam = 0

if freereinforcementid == 200
return 220 ;no free alias

PS now forum said I cant post because I am not logged :D That was very scary as English is not my native language and I thought all text is lost..

UPD just realized that some elements in array are empty :D Errors are gone, but the first part is still mysterious.

Link to comment
Share on other sites

First part - Quest scripts will process OnInit() twice. On game startup and when the quest actually Starts or resets. https://www.creationkit.com/index.php?title=OnInit 

Second part - You can also put checks for None to trap errors before they happen. Like if the alias.GetReference() != None then go ahead and process it.


edit: Also feel free to check out the scripts in OBIS SE. We've done fairly well with the dynamic spawning thing.

Edited by Jebbalon
added line +
Link to comment
Share on other sites

GetReference() cannot be called on an alias during OnInit(). It will return NONE if you do because the aliases in the quest have not yet been filled.

So whatever the reinforcement() function is doing must be trying to do something with the reference in the alias before it's been filled by the quest.

I just had to fix a big issue with this in Bring Out Your Dead.

Link to comment
Share on other sites

Thanks! I wasnt aware about double OnInit() with quests, thought about it as of some bug like double perks with unreliable behavior.

About second part and "if refaliasarray[inam] != none" I figured it out shorlty after posting, final line was about it. Aliases get into this array during their OnInit() so there are only two variant what is inside array - either none or alias with ccccwealiasscript, as only it can call function that adds it.

Also interesting part that all aliases get OnInit() as game starts as well. When quest wasnt running but script was - then I already had full array of aliases. So while alias has no ref like objectref it is already have aliasref that can be put into array or variable. In my quest script OnUpdate() was a debug function that counted aliases total, aliases with ref and alias that are for recycle. If this is how it works in a game then considering all the quests and all the aliases it makes quite the impact on preformance.

Also in my quest aliases have randomized part in the first RegisterForSingleUpdate time, so they better distribute load.


Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Create New...