#I already tried that
1 messages · Page 1 of 1 (latest)
Can you show me all your code related to this? I need to see where you're adding the listener and where Amount() belongs.
yes.
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Everything worked literally yesterday
confirm.onClick.RemoveListener(() => { Amount(); });
So if you run this code right now, "test 2" never gets printed to the console?
nope
Does React get called?
Obviously
hmmm
i am really not sure...
Why can't you just
in the inspector, assign the button's onclick event to Amount()?
hard to explain
one of the reasons is that the gameobjects that call it are clones
it's just that I can't
It's the only solution and I have no clue why it doesn't work and I'm so fucking pissd kill me
okay one more thing to try
wait I will do some analysis since I got the old version of the file as well
void Test(string someText) { Debug.Log(someText); }
...
button.AddListener(delegate { Test("Hello World"); });
does this work?
no
yeah i'm not sure then... you could try making a small dummy script that just forwards calls to Amount() and set the OnClick event in the inspector to call the dummy script.
Wait you're calling React() everyframe?
That means you're adding a listener, every. single. frame?
Are you trying to make it so the player can only click the button if a condition is met?
yes
and till yesterday it worked
like holy shit the only thing I changed is that I fixed some UI bugs nothing else
Why not just set button.interactable to false when they shouldn't be able to click it?
OR
Always let them click it, but check the condition in Amount() ?
are you here to solve your problem or continue to be mad and solve nothing?
If you're not willing to take a different approach then I'm not sure how to help you any further
look I cant just do it the unity way using OnClick()
it's hard to explain
I require this
fucking hell
@umbral yarrow would you mind if I sent you the entire file
Haven't you already in that pastebin?
uh no. I'm not interested in downloading your unity project, sorry.
ok why isn't it working I have no clue
@onyx ferry there's a thread for his issue already here.
@iron cloak you too.
they've linked their code above
Amount() is quite a big function that could die in a couple of ways. If there's an error in there, it might be silently dying without finishing the function. Try this. Add this debug log right before you call the AddClick:
Debug.Log($"Adding a listener to {confirm.gameObject.name}");
and then inside of Amount(), put in this log and comment everything else out. Let's make sure it can call the function first.
Debug.Log("Amount has been executed");
it doesn't even return test2 at the top
Update, Instance IDs seem to be different between Inspector and code, so betting on a bad reference
If it's running in another thread and it dies then it will never report back to the main thread that it needs to log something
I don't know how this is running, but I'm making a wild guess
how is this even possible is beyond me
How are you getting a reference to the button?
Okay, so create another field of the same type, drag-drop the button (make sure it's the correct one), and in the code, log if confirm == subject where subject is the field you just created.
Prints out false? You have a bad ref
alright
wait
okay so the ID is the same when it comes to button
button component ID: 20138
it's the same
my bad
it doesn't explain why it doesn't work though
Does some of the code run on another thread? If you're not dealing with threads new Thread, async/await, it's a no
(coroutines are not threaded)
nope, I'm not
So, right before you add the listener, throw new Exception("Test"), same thing in the Amount method
If you don't get any exception, then the code that adds the listener isn't running
(disregard any "Unreachable code" warnings this might create, after adding the throw instructions)
it does throw the first exception (before the listener)
Ah, debugging by destruction. The last most powerful tool of a confused developer
Okay, so it reaches that code and is definitely adding the listener. Now remove it and try to get the error to come from the first line of Amount()
Okay, so then the code is definitely quietly dying
Comment out everything that isn't the throw
/* after the throw
*/ right before the end of the function
After that verification (what digi is saying), you might need to explore if it actually adds the listener. Maybe some silenced error makes it fail?
You'll need to log confirm.onClick.GetPersistentEventCount() both before and after you add the listener. It should be printing 0, 1.
still no exception
The code snippet in https://docs.unity3d.com/ScriptReference/Events.UnityEventBase.GetPersistentListenerState.html will print out info about each registered listener, use wisely
Even when the only thing in Amount() is the throw?
yes
How about changing the add listener line to confirm.onClick.AddListener(() => throw new Exception("Test"));
Actually hang on
confirm.onClick.AddListener(() => { Amount(); });
I think this should be
confirm.onClick.AddListener(() => Amount());
Has that been tried yet?
I have another destructive debug method: making the button reference null after you add the listener, so it catches any modifications made to the button
oh god was this a anonymous scoping issue the whole time
That shouldn't be an issue, both should compile to the same thing
yes
Does this work: #988524198362239106 message ?
also, the exception was thrown
confirm.onClick.AddListener(() => throw new Exception("Test 3"));
yes
Three possible syntaxes, have you tried them all?
AddListener(() => { Amount(); });
AddListener(() => Amount());
AddListener(Amount);
let's try again
If those 3 don't work, I think we try just writing a simple script that has nothing in it other than the code we're focused on fixing
Proceed with <#988524198362239106 message>
And <#988524198362239106 message>
I will tommorow if you don't mind. I already spend 8 hours working and got school tommorow.
and it's already very late
Things to try for tomorrow
Print out listener info
Isolate the issue by writing a new, simple script with a button and a listener to see if the issue lies in Amount or outside of it
Check if the listener doesn't get cleared in between the add and the event raise
morning
when it comes to printing out listener info, do I make a new UnityEvent or what
or something along the lines of:
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
and I wrote this small script which works
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour
{
public Button confirm;
void Test2(string someText) { Debug.Log(someText); }
void Start()
{
confirm.onClick.AddListener(delegate { Test2("Hello world"); });
}
}
when it comes to clearing the listener i dont think so
To print listener info you take inspiration of the code in that page
That's what you have in the pastebin
So run that loop after you add the listener and see what it says
yeah but confirm is a button
tried that
doesn't work
UnityEngine.Component.GetComponent[T] () (at <0ee480759f3d481d82ada245dc74f9fd>:0)
InteractionRadius.React (UnityEngine.Vector3 center, System.Single radius) (at Assets/Scripts/InteractionRadius.cs:361)
InteractionRadius.Update () (at Assets/Scripts/InteractionRadius.cs:431)```
OH WAIT
huh
ok so error solved but it doesn't debug anything
like it doesn't log anything
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Log confirm.onClick.GetPersistentEventCount() just before the loop
0
Add a dummy listener and retry
Not sure it'll even work, those methods get persistent listeners, the ones added at runtime might not be persistent
still no
So these aren't persitent
Onto the next step
Remove the dummy listener, and right after you add the listener that doesn't work, set confirm to null
Then play the game. As soon as you get a NullRef, stop the game and inspect the line it got thrown on to see if you're messing with the listeners at that point.
If you're not, then put the confirm = null after the point the exception was thrown, and repeat the steps
confirm.onCLick.AddListener(Amount);
confirm = null;
The troubleshooting stops when you don't get NullRefs anymore
...i'm not getting any NullRefs at the first step
So you're not modifying the button afterwards
That is the worst possible outcome
The listener gets removed silently at some point
Or, it's accessed from another script. Try: DestroyImmediate(confirm), then confirm = null;, and see if you get any errors
without adding the listener?
It won't make any difference, but you can add it
InteractionRadius.React (UnityEngine.Vector3 center, System.Single radius) (at Assets/Scripts/InteractionRadius.cs:361)
InteractionRadius.Update () (at Assets/Scripts/InteractionRadius.cs:432)```
Debug.Log(confirm.onClick.GetPersistentEventCount());
should I comment it
No, you move the DestroyImmediate and confirm = null below that line
ok
along side this, correct?
NullReferenceException: Object reference not set to an instance of an object
InteractionRadius.React (UnityEngine.Vector3 center, System.Single radius) (at Assets/Scripts/InteractionRadius.cs:362)
InteractionRadius.Update () (at Assets/Scripts/InteractionRadius.cs:432)
NullReferenceException: Object reference not set to an instance of an object
InteractionRadius.React (UnityEngine.Vector3 center, System.Single radius) (at Assets/Scripts/InteractionRadius.cs:359)
InteractionRadius.Update () (at Assets/Scripts/InteractionRadius.cs:432)
line 362: for (int i = 0; i < confirm.onClick.GetPersistentEventCount(); ++i)
Debug.Log(confirm.onClick.GetPersistentEventCount()); line 359
Move the destruction and the set to null after line 362
Outside of the for loop (after the loop)
no errors now
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
This is not after the for loop...
Alright. You said you can't start the debugger right?
yes
So, make a new object with a button on it, and add Amount as the listener like you're already doing with confirm
You'll just have to declare another variable to reference the temporary button
still fucking nothing
I'm afraid I have nothing else to suggest
Apart from deleting the entire object, re-creating it and linking the references again
object as in?
The one that has the button, and the one that has the script that adds a listener, if they're on different objects
I see. Thanks for your time though
At least I'm not the only one stumped haha
what the fuck
@onyx ferry you know what
I might as well pay you if you help me
I'm out of ideas
I might send you the entire project ig
I mean the only thing I changed
is some UI related stuff, aka scale etc
nothing
fucking
else
I would have suggested checking if you can inspect the event with the debugger, to see if you have access to the listener collections, but it doesn't work on your side
What Unity version are you on?
2020.3.25f1
I have 2020.3.3f1 installed on my side. I'll test some stuff
Yeah why not, at this point
ok DM since you know, private/confidential stuff
I mean not that it's secret
it's the files
you get the idea
Sure
Okay it's open, I'll need you to guide me through it
Alright
The issue is within the InteractionRadius.cs file
it is located within the Scripts folder
The button which the listener "operates" on is located in the following hierarchy:
EventSystem > Canvas > InputAmount > Button
Line 311 of InteractionRadius was for debugging purposes right
confirm.onClick.RemoveListener(Amount);, it's in Amount so it shouldn't interfere
Unless Amount is called manually, which isn't the case
Alright now, how do I get to that button in game?
Getting exceptions when trying to instantiate an element from the periodic table
Investigating...
ArgumentException: method arguments are incompatible
wait did I send you the database
Weird
It printed out elements to the console when starting the game, so I assume that was the database
I have a lot of random ones lol
Oh boy
Editor throwing, shader graph dying etc
It's not runtime, so I assume this doesn't cause issues
ah
Wait did you open the project or did it open straight up the main "Screen"?
Like did it open the menu first
but that wouldn't change much.
I opened the project by double clicking the only scene file present in Assets/Scenes/
Okay managed to fix the instantiate button error
what caused it?
There was a handler in the On Click inspector list that was just empty lol
No idea what caused it, removed it and error went away
I have the dreaded "Confirm" button in sight now
It says "Hello World" when I click it
Nope, the screen doesn't go away
let me double check if it has the proper handler just in case
this still didn't get solved? D:
I told you it's cursed
I can feel the evil from this script ten miles away
it's the soviets slowing down the progress on western science
and yes it's the same listener
why the fuck it doesn't work
The listener gets added to the internal listeners array of the onclick event
But doesn't get called
Debugger never hits the breakpoint
rip
have you tried just remaking the button/prefab?
Ahh I think I got it
oh please do share
The handler does not run if this is captured in the lambda expression, which means this doesn't exist anymore when the event is raised. And surely, the whole object is destroyed right after the UI button is shown
Case solved
that makes sense, but how is this being captured in a statement like
button.onClick.AddListener(() => Amount()); ?
Amount is a method that's declared on the MonoBehaviour, so to resolve the scope it has to capture the whole class
So what would be the recommended fix there?
And commenting out the two Destroy calls run the handler!
Have a separate script to run the handler on, that never gets destroyed
let's gooo
So, full explanation of the story and how to fix.
I started putting breakpoints pretty much everywhere to see how the execution flows through the program.
You can place chemistry elements on a table, and fill these elements with either raw chemical elements, or compounds (like water). Then, if you combine two containers (say one flask of Na and one of H2O), it asks you how many there are to combine, so it does the reaction realistically with the stoichiometry and whatnot. The issue lies there, when you click on the "Confirm" button to combine the two containers into one, the handler does not get run.
After that I focused on the handler addition that worked half of the time, literally. The following worked
button.onClick.AddListener(() => Debug.Log("test"))
While that one didn't
button.onClick.AddListener(() => Amount())
So I moved on and tried this: () => Debug.Log(this.gameObject.name), and suddenly it wasn't getting called anymore. That's pretty much where it clicked: if I included a reference to the script or the object itself, it stopped logging. In other words, if the lambda captured this in its scope, nothing would happen.
The only reason for that to occur is if this didn't exist anymore at the time the event was raised. And with Unity, it means the object got destroyed.
So I scrolled down the method until I hit the dreaded two instructions that caused it all, Destroy(gameObject) and Destroy(other.gameObject).
The handler does not run because there is no object to run it on anymore.
I commented out the two Destroy instructions and played the game again. Added a few containers and components, combined them and the two quantity inputs and the button appeared. I hastily added random quantities and hit "Confirm".
Unity froze. "Oh no", I told myself for a bit. Then I saw it. The Visual Studio icon in the task bar was blinking orange. I switched to it, and to my delight the debugger had hit the breakpoint in the Amount method.
You would make a fortune as a writer
@onyx ferry mind sending me the file that you modified?
if you wouldn't mind, of course
if you added other stuff to the game itself I would really appreciate the whole project being sent over. And yes, I will proceed to pay you
To respect the "don't distribute" statement I encrypted the files with a random key then deleted them, ie. they're not recoverable.
I have the fix in mind though. You would need to make the Amount method on an object that does not get destroyed, or in a separate class completely, and pass the required info as arguments to the method.
My guess would be on the UI element where you input the quantities and confirm. That one doesn't get destroyed at all. You would just need to store the required info prior to calling it.
The subscription can still be done in your React method as long as the lambda does not capture this
fixed it, thank you so much ❤️
send me your email so I can send the cash via paypal
You're good. I don't have paypal anyway lol
I've been doing this in my free time for more than a year and never received compensation for it, that's not going to change today