Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Bug when printing external function conditional in choice text #98

Open
ringlas opened this issue Feb 26, 2025 · 3 comments
Open

Bug when printing external function conditional in choice text #98

ringlas opened this issue Feb 26, 2025 · 3 comments
Labels
bug Something isn't working

Comments

@ringlas
Copy link

ringlas commented Feb 26, 2025

Describe the bug

When using an external function in an Ink script to evaluate a simple conditional check (e.g., checking if an integer variable is greater than a value), godot-ink throws an error during execution.

The error message suggests that the Ink runtime is attempting to pop too many objects from the evaluation stack, leading to a System.Exception: trying to pop too many objects.

To Reproduce

  1. Create fresh project on Godot 4
  2. Follow QuickStartGuide from the docs: https://github.com/paulloz/godot-ink/wiki#quickstartguidecs
  3. Create an Ink script containing an external function that returns an integer.
  4. Use this function to print the evaluation of a conditional statement inside a choice.
  5. NB! Don't use it as a conditional for the choice visibility, but print its result within the choice's text.
  6. Load and run the story in Godot using godot-ink.
  7. Observe the crash with the error message.

Example Ink Script:

VAR money = 2

Once upon a time... 

* There were {get_money() >= 2} two choices.

* There were four lines of content.

- They lived happily ever after.
    -> END

=== function get_money() 
    ~ return 12

EXTERNAL get_money()

Example C# Code

using Godot;
using GodotInk;

public partial class QuickStartGuide : VBoxContainer
{
    [Export]
    private InkStory story;

    public override void _Ready()
    {
        story.BindExternalFunction("get_money", Callable.From(GetMoney));

        ContinueStory();
    }

    private void ContinueStory()
    {
        foreach (Node child in GetChildren())
            child.QueueFree();

        Label content = new() { Text = story.ContinueMaximally() };
        AddChild(content);

        foreach (InkChoice choice in story.CurrentChoices)
        {
            Button button = new() { Text = choice.Text };
            button.Pressed += delegate
            {
                story.ChooseChoiceIndex(choice.Index);
                ContinueStory();
            };
            AddChild(button);
        }
    }

    private int GetMoney()
    {
        return 5;
    }
}

Expected

The conditional check {get_money() >= 2} should resolve properly within the text, allowing the game to continue execution.

Actual

Godot throws the following error when executing the script:

E 0:00:01:0997   System.Collections.Generic.List`1[Ink.Runtime.Object] Ink.Runtime.StoryState.PopEvaluationStack(int): System.Exception: trying to pop too many objects
  <C++ Error>    System.Exception
  <C++ Source>   :0 @ System.Collections.Generic.List`1[Ink.Runtime.Object] Ink.Runtime.StoryState.PopEvaluationStack(int)
  <Stack Trace>  :0 @ System.Collections.Generic.List`1[Ink.Runtime.Object] Ink.Runtime.StoryState.PopEvaluationStack(int)
                 :0 @ bool Ink.Runtime.Story.PerformLogicAndFlowControl(Ink.Runtime.Object)
                 :0 @ void Ink.Runtime.Story.Step()
                 :0 @ bool Ink.Runtime.Story.ContinueSingleStep()
                 :0 @ void Ink.Runtime.Story.ContinueInternal(float)
                 :0 @ string Ink.Runtime.Story.ContinueMaximally()
                 InkStory.cs:108 @ string GodotInk.InkStory.ContinueMaximally()
                 QuickStartGuide.cs:21 @ void QuickStartGuide.ContinueStory()
                 QuickStartGuide.cs:13 @ void QuickStartGuide._Ready()

Environment

  • OS: Windows 10
  • Godot version: 4.3
  • godot-ink version: 1.1.2
  • ink version: 1.1.1

Additional context

The issue does not occur when the external function is used normally (e.g., printing its value in text without a conditional).
It seems related to evaluating the function call inside an inline conditional check ({get_money() >= 2}).
Possibly an issue with how godot-ink handles inline evaluations of external function calls.

Workarounds include manually storing the function's return value in a variable before using it in a condition.

@ringlas ringlas added the bug Something isn't working label Feb 26, 2025
@ringlas
Copy link
Author

ringlas commented Feb 26, 2025

P.S: Fantastic work on this add-on, highly appreciated!

@ringlas ringlas closed this as completed Feb 26, 2025
@paulloz paulloz reopened this Feb 26, 2025
@paulloz
Copy link
Owner

paulloz commented Feb 26, 2025

I'd be curious to see if this is reproducible outside both Godot and Godot-ink, just using the ink runtime in a bare bone C# application.

@ringlas
Copy link
Author

ringlas commented Feb 26, 2025

I am not sure how to test that though... I can confirm that it doesn't happen in any of my Unity projects using different versions of the Unity Ink runtime.

This is a workaround within Ink to avoid the behaviour in Godot.

~ temp characters_money = get_money()
    
+ [<{characters_money >= 2}>Pay her two gold pieces.]

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants