Jump to content

Post for JIP


Recommended Posts

Hi this post is an example of a bug with SetGameMainLoopCallback...

 

Esp using the scripts below:

 

What the esp does:
The player holds right click on an actor for roughly 3 secs and a script is added to the actor.
All the actor script does is count to 10 secs reporting to the console and removes itself.

If you only target one actor, let the actor finish the count, the player script stays on fine.

To see the bug simply go where there are 2 actors that you can target seperately while holding right click.
Target one actor and then target the next actor so both have a script attached.

Both actors have the script on them, but the player script just stops for no reason what so ever.
At no point is the player script meant to stop and nothing calls it to stop either.
Watching the console you can see the player script stops just after the 2nd actor gets a script added.

I'll provide another example that works differently not even based on the player at all, but the bug still happens.
The src script gets dropped for no logical reason what so ever that I can see.

 

 

Quest script to add the player callback:

Scn SGMLCQuestScr



Begin GameMode

    If GetGameRestarted

        PlayerRef.SetGameMainLoopCallback SGMLCPlayerScr 1 180 1

    EndIf

End

Player Callback UDF (Added via quest script on GetGameRestarted):

Scn SGMLCPlayerScr



Ref rActor



Begin Function {}

    PrintC "SGMLCPlayerScr Start (Spam every 3 Secs == 180 Frames)"

    If (IsControlPressed 6)

        Let rActor := ObjectUnderReticle 0 6144

        If (rActor != 0) && (IsFormValid rActor) && (IsReference rActor)

            If (rActor.GetType == 42) && (0 == rActor.AuxVarGetFlt "*SGMLC" 0)

                MessageEx "%n notices you looking at %po." rActor rActor

                rActor.FaceObject PlayerRef

                rActor.AuxVarSetFlt "*SGMLC" 1 0

                PrintC "SGMLCPlayerScr Add SGMLCActorScr To [%i] %n" rActor rActor

                rActor.SetGameMainLoopCallback SGMLCActorScr 1 6 1

            EndIf

        EndIf

    EndIf

End

NPC Calback UDF (Get Added via Player Callback UDF):

Scn SGMLCActorScr



Ref rActor

Int i



Begin Function {}

    Set rActor To this

    Set i To 1 + rActor.AuxVarGetFlt "*SGMLC" 0

    If (i < 101)

        rActor.AuxVarSetFlt "*SGMLC" i 0

        If (i % 10) == 0

            Let i /= 10

            PrintC "[%i] %n SGMLCActorScr active for %g Seconds" rActor rActor i

        EndIf

    Else

        PrintC "[%i] %n Remove SGMLCActorScr" rActor rActor

        rActor.AuxVarErase "*SGMLC"

        rActor.SetGameMainLoopCallback SGMLCActorScr 0

    EndIf

End

I have tried using a custom DispatchEvent from the SGMLCPlayerScr to call a another UDF to set the SGMLCActorScr and still the same result player script stops firing after the second actor has their script added.

 

Yet adding the Target Actor to a Formlist and having a quest loop the the list and adding the SGMLCActorScr to the actors, then the player script stays intact and functional forever.

 

 

Edit:

I tried using your new RunSnippet function and it bypasses the player script being dropped.

Basically I edited the above SGMLCPlayerScr to this and the bug disappears:

Scn SGMLCPlayerScr

Ref rActor
Ref SGMLCScr

Begin Function {}
    PrintC "SGMLCPlayerScr Start (Spam every 3 Secs == 180 Frames)"
    If (IsControlPressed 6)
        Let rActor := ObjectUnderReticle 0 6144
        If (rActor != 0) && (IsFormValid rActor) && (IsReference rActor)
            If (rActor.GetType == 42) && (0 == rActor.AuxVarGetFlt "*SGMLC" 0)
                MessageEx "%n notices you looking at %po." rActor rActor
                rActor.FaceObject PlayerRef
                PrintC "SGMLCPlayerScr Add SGMLCActorScr To [%i] %n" rActor rActor
                rActor.AuxVarSetFlt "*SGMLC" 1 0
                Set SGMLCScr To SGMLCActorScr
                rActor.RunScriptSnippet 1 "Ref A%rRef S%rSet A To %q%i%q%rSet S To %q%i%q%rA.SetGameMainLoopCallback S 1 6 1" rActor SGMLCScr
            EndIf
        EndIf
    EndIf
End

Which seems odd.

It's definitely a timing issue.

If I set the RunScriptSnippet to a 0 Delay then the bug returns.

 

Seems odd though as the script delay in in either of the SetGameMainLoopCallback scripts is not at 1 frame.

Doesn't matter what delays i use in the SetGameMainLoopCallback, the bug still appears if I call it directly.

Edited by sLoPpYdOtBiGhOlE
Link to comment
Share on other sites

Nothing to do with your problem but I feel I should point out that

If (rActor != 0) && (IsFormValid rActor) && (IsReference rActor)

can crash your script if rActor doesn't hold a valid form, because IsReference will freak out over it and the IsFormValid check does nothing to prevent it. You need to break that line up into two:

if IsFormValid rActor

if IsReference rActor

 

I'd omit (rActor != 0) because it's superfluous.

Link to comment
Share on other sites

Thank you for the input.

 

So papyrus processes the whole line before stopping the condition check when using && operators?

eg:

 

If (rActor != 0) "condition not met stop before going any further" && (IsFormValid rActor) "condition not met stop before going any further" && (IsReference rActor)

 

In all honesty I have been running that same check on over 30 NPCs at the same time every frame running for hours on end over the past year or so and not had a single crash from calling a function on a nul ref as of yet.


And I actually use that same line intentionally to catch purposeful nul refs and still never crashed yet.

When i didn't have the IsReference in the line, that's when forms could slip through.

If I only use IsRefernce then I also get the odd crash.

 

I do see what your saying and i do quite often use line by line checks, but mainly when using CO, which I try to avoid using

 

In relation to my original problem:

When or if the script fails and the game doesn't CTD then you usually see console spam saying the script ID and offset that failed.

Which isn't the case for the problem I'm having.

I don't get any errors or CTDs

Edited by sLoPpYdOtBiGhOlE
Link to comment
Share on other sites

OB/Geckscript processes the whole line, yes, so if the ref var holds an invalid form or none at all, it will be passed to IsReference, and the IsFormValid check doesn't stop that - the only way to prevent it is to split up the line. I'm not entirely sure anymore if IsReference will cause a script crash if passed an invalid form, but it obviously becomes an issue if you use a function with ref syntax in such lines, so overall it's just good practice to stagger your validity checks, even if does cost you a few extra lines.

 

In regards to your issue, I'm not familiar with the new jip functions yet, but it's entirely possible for scripts to crash and not cause NVSE errors in the console. I call that a silent crash, and from what you're describing (a script not running again when it's supposed to) it could be a case of that - there are times when a script that's crashed the first time around isn't allowed to run again, especially when no errors were reported by NVSE. The only way to make sure a script runs from beginning to end is to add print lines while you're testing it. In some cases where I just didn't see what the issue could be I added them before and after every single script line just to find out where the problem was.

Link to comment
Share on other sites

Thank you for the clarification it's appreciated.

 

The issue with the function was resolved.

JIP did a rewrite of the SetGameMainLoopCallback function and it nails the issues I had completely.

I made no code changes to my code (apart from removing work arounds), just dropped in an updated jip plugin and ran my code (thrashed my code would be a better description) and the bug completely disappeared.

 

JIP is one hell of a coder that's for sure.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...