Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Rigidity slider breaks when trying to move it at exactly 0 MP #4150

Open
hhyyrylainen opened this issue Feb 22, 2023 · 8 comments · May be fixed by #5778
Open

Rigidity slider breaks when trying to move it at exactly 0 MP #4150

hhyyrylainen opened this issue Feb 22, 2023 · 8 comments · May be fixed by #5778

Comments

@hhyyrylainen
Copy link
Member

It looks like rigidity slider does a divide by zero to end up with ridiculously wrong numbers when it tries to move when there's exactly 0 MP left. This can be triggered with a very specific MP cost multiplier to be able to place parts to reach 0 MP and then trying to move the rigidity slider.

https://community.revolutionarygamesstudio.com/t/membrane-rigidity-visual-bug/6059

Video: https://youtu.be/9c4ekW5QNI8

@84634E1A607A
Copy link
Contributor

https://github.com/Revolutionary-Games/Thrive/blob/master/src/microbe_stage/editor/CellEditorComponent.cs#L961

This can be 0. I remember we discussed before that MP should be a float instead of int. When that is done this bug should go away.

@hhyyrylainen
Copy link
Member Author

I guess that is kind of unavoidable anyway with MP discounts etc. Though, we absolutely don't want to show really long decimal values to the user in the MP bar or tooltips.

@CoreyHendrey
Copy link
Contributor

CNR_RigidityBug.mp4

Can't seem to reproduce this, the membrane slider doesn't move with 0 MP.

@CoreyHendrey
Copy link
Contributor

CoreyHendrey commented May 1, 2024

A possible(?) division by zero, I guess, would be this costPerStep:

if (cost > Editor.MutationPoints)
  {
      int stepsToCutOff = (int)Math.Ceiling((float)(cost - Editor.MutationPoints) / costPerStep);
      data.NewRigidity -= (desiredRigidity - previousRigidity > 0 ? 1 : -1) * stepsToCutOff /
          Constants.MEMBRANE_RIGIDITY_SLIDER_TO_VALUE_RATIO;

      // Action is enqueued or canceled here, so we don't need to go on.
      UpdateRigiditySlider((int)Math.Round(data.NewRigidity * Constants.MEMBRANE_RIGIDITY_SLIDER_TO_VALUE_RATIO));
      return;
  }

But if we want, we could just do,

if (cost > Editor.MutationPoints && costPerStep > 0)
  {
      int stepsToCutOff = (int)Math.Ceiling((float)(cost - Editor.MutationPoints) / costPerStep);
      data.NewRigidity -= (desiredRigidity - previousRigidity > 0 ? 1 : -1) * stepsToCutOff /
          Constants.MEMBRANE_RIGIDITY_SLIDER_TO_VALUE_RATIO;

      // Action is enqueued or canceled here, so we don't need to go on.
      UpdateRigiditySlider((int)Math.Round(data.NewRigidity * Constants.MEMBRANE_RIGIDITY_SLIDER_TO_VALUE_RATIO));
      return;
  }

Because the cost no longer matters, if the step cost is 0.

@hhyyrylainen
Copy link
Member Author

The slider is disabled when at 0 MP, but I think you can still trigger this bug by moving the slider while you still have MP but running out at exactly the mid point. Or a more reproducible way to trigger this is probably to modify new game settings to reduce the mutation costs so that steps are sometimes free and sometimes cost MP.

Also there exists a full fix for this problem here, but this PR was never finished: #4154

@hhyyrylainen hhyyrylainen moved this to started but stuck (help wanted) in Thrive Planning Aug 7, 2024
@hhyyrylainen
Copy link
Member Author

Seems like there's a new variant:

  • Set mutation cost to 0.4
  • Enter editor, pick a new membrane and place cytoplasm to use up all MP
  • Then try to move the rigidity slider
  • This will cause an infinite loop and freeze the game

This is the repeating callstack:

10069:	Godot.Bridge.CSharpInstanceBridge.Call(IntPtr, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_variant**, Int32, Godot.NativeInterop.godot_variant_call_error*, Godot.NativeInterop.godot_variant*)
10070:	[internal]
10071:	[internal]
10072:	ILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr, Void**, Void*)
10073:	Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr, IntPtr, Void**, Void*)
10074:	Godot.NativeCalls.godot_icall_1_120(IntPtr, IntPtr, Double)
10075:	Godot.Range.SetValue(Double)
10076:	Godot.Range.set_Value(Double)
10077:	CellEditorComponent.UpdateRigiditySlider(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1738
10078:	CellEditorComponent.OnRigidityChanged(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1280
10079:	CellEditorComponent.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant ByRef) at /home/hhyyrylainen/Projects/Thrive/.godot/mono/temp/obj/Debug/Godot.SourceGenerators/Godot.SourceGenerators.ScriptMethodsGenerator/CellEditorComponent_ScriptMethods.generated.cs:616
10080:	Godot.Bridge.CSharpInstanceBridge.Call(IntPtr, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_variant**, Int32, Godot.NativeInterop.godot_variant_call_error*, Godot.NativeInterop.godot_variant*)
10081:	[internal]
10082:	[internal]
10083:	ILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr, Void**, Void*)
10084:	Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr, IntPtr, Void**, Void*)
10085:	Godot.NativeCalls.godot_icall_1_120(IntPtr, IntPtr, Double)
10086:	Godot.Range.SetValue(Double)
10087:	Godot.Range.set_Value(Double)
10088:	CellEditorComponent.UpdateRigiditySlider(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1738
10089:	CellEditorComponent.OnRigidityChanged(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1280
10090:	CellEditorComponent.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant ByRef) at /home/hhyyrylainen/Projects/Thrive/.godot/mono/temp/obj/Debug/Godot.SourceGenerators/Godot.SourceGenerators.ScriptMethodsGenerator/CellEditorComponent_ScriptMethods.generated.cs:616
10091:	Godot.Bridge.CSharpInstanceBridge.Call(IntPtr, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_variant**, Int32, Godot.NativeInterop.godot_variant_call_error*, Godot.NativeInterop.godot_variant*)
10092:	[internal]
10093:	[internal]
10094:	ILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr, Void**, Void*)
10095:	Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr, IntPtr, Void**, Void*)
10096:	Godot.NativeCalls.godot_icall_1_120(IntPtr, IntPtr, Double)
10097:	Godot.Range.SetValue(Double)
10098:	Godot.Range.set_Value(Double)
10099:	CellEditorComponent.UpdateRigiditySlider(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1738
10100:	CellEditorComponent.OnRigidityChanged(Int32) at /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/CellEditorComponent.cs:1280
10101:	CellEditorComponent.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant ByRef) at /home/hhyyrylainen/Projects/Thrive/.godot/mono/temp/obj/Debug/Godot.SourceGenerators/Godot.SourceGenerators.ScriptMethodsGenerator/CellEditorComponent_ScriptMethods.generated.cs:616
10102:	Godot.Bridge.CSharpInstanceBridge.Call(IntPtr, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_variant**, Int32, Godot.NativeInterop.godot_variant_call_error*, Godot.NativeInterop.godot_variant*)

So the problem is that CellEditorComponent.OnRigidityChanged(Int32) at src/microbe_stage/editor/CellEditorComponent.cs:1280 constantly tries to change the slider value but it's probably less than the step size so it gets stuck infinitely adjusting things.

@hhyyrylainen hhyyrylainen moved this from started but stuck (help wanted) to High priority bugs / issues in Thrive Planning Dec 28, 2024
@CI09
Copy link
Contributor

CI09 commented Dec 28, 2024

If step is too big, we can decrease it to fit mutation points modifier (0.4), and min/max slider values to keep proportion. Is this approach good or am I missing something?

@hhyyrylainen
Copy link
Member Author

When dragging with the mouse the slider emits value change events for each step, meaning that decreasing step size will dramatically increase the number of rigidity change events that are generated. And also for keyboard input it will become impossible at some point to use the left / right arrows to change the value in a reasonable amount of time (so this will make future controller input not usable). So those are the problems, which is why I have not suggested trying to modify the minimum step size, but instead I think something else needs to be done.

@Patryk26g Patryk26g linked a pull request Dec 29, 2024 that will close this issue
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: High priority bugs / issues
4 participants