sLoPpYdOtBiGhOlE Posted July 28, 2017 Share Posted July 28, 2017 (edited) 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 EndPlayer 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 EndNPC 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 EndI 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 EndWhich 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 July 28, 2017 by sLoPpYdOtBiGhOlE Link to comment Share on other sites More sharing options...
DoctaSax Posted July 28, 2017 Share Posted July 28, 2017 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 More sharing options...
sLoPpYdOtBiGhOlE Posted July 29, 2017 Author Share Posted July 29, 2017 (edited) 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 July 29, 2017 by sLoPpYdOtBiGhOlE Link to comment Share on other sites More sharing options...
DoctaSax Posted July 29, 2017 Share Posted July 29, 2017 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 More sharing options...
sLoPpYdOtBiGhOlE Posted July 30, 2017 Author Share Posted July 30, 2017 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 More sharing options...
Recommended Posts