snozbot / fungus

An easy to use Unity 3D library for creating illustrated Interactive Fiction games and more.
MIT License
1.63k stars 290 forks source link

A Way to Delay Loading or Invoke Method to prevent "Exception has been thrown by the target of an invocation" when loading save #960

Closed TheEmbracedOne closed 3 years ago

TheEmbracedOne commented 3 years ago

Problem:

I have a savepoint on most blocks and most of them are set to "resume on load". When a save is loaded from the main menu and the starting block happens to have an Invoke Method command right after the SavePoint, it throws an error: Error: Exception has been thrown by the target of an invocation. image

If I do right click>stop then execute the same block, it goes through without the error, which makes me think it attempts doing the Invoke Method command before the target of said Invoke Method has finished loading.

I tried putting the relevant script at -4000+ in the script execution order, but it didnt make a difference.

Workaround:

Right now I can work around this by inserting a 0.5s Wait command right between the SavePoint and Invoke Method.

Desired Solution:

It'd be great if I could make some modifications so that on Awake Fungus doesnt immediately start executing for 0.5s or so when loading a save, OR to add a bit of delay into the Invoke Method or SavePoint commands.

Which option is better? Or is there another way?

Arylos07 commented 3 years ago

More than likely, you have that block set to use the Game Started event. You can change this to an On Message Received if you want to send a trigger like message to tell the block to run. (Or set On Execute Event to none and call the block from script manually)

Otherwise, Game Started has a "wait for frames" property. The game waits that number of frames before executing the block. Set it to something like 30/60 and that should resolve your issue.

Screenshot_121 (Ignore attributes that normally aren't in Fungus here; I modified blocks in my project to act differently)

TheEmbracedOne commented 3 years ago

@Arylos07 hey, thanks for the reply. I dont have the block set to "Game Started" - it's set to none; in fact I only ever use "None" throughout the entire game because I'm using autosave. image

(Or set On Execute Event to none and call the block from script manually)

Isn't using the Load functionality of Fungus essentially the equivalent of calling a block manually? The problem described in OP is only a problem if the following is true: SavePoint that is being loaded from the main menu using Fungus' load functionality has an "Invoke Method" right after, as per my screenshot above. If I insert the 0.5s Wait between the SavePoint and Invoke Method, it works just fine.

Otherwise, Game Started has a "wait for frames" property. The game waits that number of frames before executing the block. Set it to something like 30/60 and that should resolve your issue.

This sounds like it could be just what I need! ... but as I said there is not a single block in my scene that has "Game Started"! I am unable to set "Wait for Frames" unless "Execute on Event" is set to Game Started, but as I said I'm not using this functionality... Is there any other way to enable "Wait for Frames" other than this?

Arylos07 commented 3 years ago

Okay, I see what's going on here. Sadly, there is no way to delay the Save Point command itself that I know of; not without doing some rewriting. So it probably would be best to just add a wait command after each save point.

I didn't catch that since I haven't used the save system much as I usually write my own and there I use delays or manual calls.

stevehalliwell commented 3 years ago

I assume this is for the live save system in 3.13. So it may already be solved by the rework that is targetting 3.14. But to confirm that, any more details on the circumstance would be great to have so we can bulk up the test cases on the new save system.

Out of curiousity, does a wait 1 frame also solve the problem? My assumption is your invoke calls into something that is reliant on unity lifecycle, it's just been made and needs it's Start to run before it is safe to use. If wait 1 frame solves that then the assuption seems likely.

TheEmbracedOne commented 3 years ago

I have not been able to reproduce this issue for the past two weeks since you posted your question @stevehalliwell It might have been to do something with my custom stat manager which I've majorly polished since. I'll close this issue since it no longer occurs and I havent been able to repro it since.

TheEmbracedOne commented 3 years ago

Today I ran into this issue once again. I tried the 1 frame wait, it doesnt work. But it works with a 2 frame wait!

The flowchart in question had a node set to "Game Started" and its first command is a custom command that starts up the exploration system of my game. A part of this initialisation involves querying some values from my Databox database that is essentially my player save, and that is where things went wrong, because the querying happens with a 0.01f delay on Awake, therefore the querying happened before the database loaded properly.

Putting in a 2frame wait allows the database to initialise properly, and it all works just fine.

breadnone commented 3 years ago

You can work around this via Unity's Script execution order, if you had to

TheEmbracedOne commented 3 years ago

I have set up Script execution order, and Fungus loads pretty much after all my save-related components, however because there was a delay on awake, script execution didnt matter. I removed the wait and it's all good now.