Announcement

Collapse
No announcement yet.

Who is setting my BOOL variable to true?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Who is setting my BOOL variable to true?

    Hello.

    I have a Projectile class with a method called OnImpact() which gets called as soon as the projectile actually hits something

    Code:
    void AProjectile::OnImpact(const FHitResult& HitResult, bool forceExplosion = false)
    {
    	if (Role == ROLE_Authority)
    		OnProjectileImpact(HitResult, forceExplosion);	
    }
    As you can see, the parameter forceExplosion is by default set to false.

    The problem is that when I hop in game, the variable is true!

    I don't understand how.

    In the Projectile constructor I have this delegate:

    Code:
    // When the projectile hits something
    MovementComponent->OnProjectileStop.AddDynamic(this, &AProjectile::AddDynamicOnImpact);
    So the function AddDynamicOnImpact() should be called when the Projectile hits something, right?

    Apparently it doesn't because the string "Hello, I am the delegate!" doesn't appear on the screen!

    Code:
    void AProjectile::AddDynamicOnImpact(const FHitResult& HitResult)
    {
    	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("HELLO, I AM THE DELEGATE!")));
         
            // HERE I CALL OnImpact() passing FALSE as argument!
    	OnImpact(HitResult, false);
    }
    I tried to take a look at the Call Stack provided by Visual Studio:

    Click image for larger version

Name:	123.jpg
Views:	1
Size:	498.4 KB
ID:	1204407

    Any help?
    Attached Files
    Last edited by gedamial; 12-22-2016, 07:14 PM.

    #2
    According to call stack your OnImpact is called from some script place, not from AddDynamicOnImpact
    Maybe you are binding it elsewhere.
    And show your header file.

    PS. And you are debugging Grenades, aren't the supposed to be Explosive? )
    Last edited by Yata; 12-23-2016, 01:53 AM.

    Comment


      #3
      I'd try to dig down into MovementComponent->OnProjectileStop in the VS watch window, to try to find what function(s) are bound. It looks from the call stack as if OnImpact is itself directly bound. Were you perhaps binding this previously, or changed the name of a method?

      I had issues in the past with old bindings persisting after I changed the code, especially when blueprints were involved. Since then, I always try to avoid binding dynamic delegates in constructors, and do it in BeginPlay instead. If you have a blueprint based on this class, I'd suggest recreating it, or a new blueprint, and seeing if you still get this behaviour.

      Comment


        #4
        Originally posted by Yata View Post
        According to call stack your OnImpact is called from some script place, not from AddDynamicOnImpact
        Maybe you are binding it elsewhere.
        Elsewhere? Apparently not. This is the Blueprint, which hasn't any reference to the OnImpact() function...

        Click image for larger version

Name:	1.jpg
Views:	1
Size:	317.5 KB
ID:	1120467

        I did everything by code...

        Originally posted by Yata View Post
        PS. And you are debugging Grenades, aren't the supposed to be Explosive? )
        Projectile is the base class of Projectile_Explosives

        Originally posted by Yata View Post
        And show your header file.
        Code:
        public:
        	AProjectile();
        	virtual void PostInitializeComponents() override;
        	virtual void PostInitProperties() override;
        	virtual void BeginPlay() override;
        	virtual void Tick(float DeltaTime) override;
        
        	/* Called when the projectile touches something */
        	UFUNCTION()
        		void OnImpact(const FHitResult& HitResult, bool forceExplosion = false);
        	UFUNCTION()
        		void AddDynamicOnImpact(const FHitResult& HitResult);
        
        	/* setup velocity */
        	void InitVelocity(FVector& ShootDirection);
        Originally posted by kamrann View Post
        It looks from the call stack as if OnImpact is itself directly bound. Were you perhaps binding this previously, or changed the name of a method?
        So the OnImpact function is directly called when the projectile hits something? Seems legit.

        But then why is my bool variable set to true by default? Despite of the = false in the header?


        Originally posted by kamrann View Post
        Since then, I always try to avoid binding dynamic delegates in constructors, and do it in BeginPlay instead.
        Many people have always told me to set delegates in the constructor. The ShooterGame example also does it. Can't understand where to put this freaking delegates!!!

        Comment


          #5
          Yeah I know it's often done in the constructor, and it should work, I just personally try to avoid it since wasting a huge amount of time once tracking down an issue that turned out to be caused by corrupted delegate bindings in a blueprint after changing the C++ code. If you bind delegates in BeginPlay, then they won't ever be serialized so that can't happen.

          It does seem strange that it's coming through as true, but it's possible that could happen if the binding is corrupted and is attached to a function with an unexpected signature (OnProjectileStop expects only 1 argument, so if it's somehow got bound directly to OnImpact, the second argument could end up being anything). Maybe confirm the underlying value of forceExplosion in the debugger - if it's 1, then I doubt this is the issue, but if it's anything other than 0 or 1, then this could be it.

          Comment


            #6
            Originally posted by kamrann View Post
            It does seem strange that it's coming through as true, but it's possible that could happen if the binding is corrupted and is attached to a function with an unexpected signature (OnProjectileStop expects only 1 argument, so if it's somehow got bound directly to OnImpact, the second argument could end up being anything). Maybe confirm the underlying value of forceExplosion in the debugger - if it's 1, then I doubt this is the issue, but if it's anything other than 0 or 1, then this could be it.
            The only thing the debugger tells me is that the variable is true (as shown in the screenshot).

            I tried moving the delegate into the BeginPlay() method but still it's like it is never called.

            Who is calling my OnImpact()?

            I have no ideas

            Comment


              #7
              If you open the Watch/Quickwatch window and enter (int)forceExplosion, it should show you the value.
              If the delegate is stored corrupted, moving it to BeginPlay now won't help. Though you could try (in BeginPlay) adding
              Code:
              MovementComponent->OnProjectileStop.Clear();
              before re-binding it.

              Comment


                #8
                Originally posted by kamrann View Post
                If the delegate is stored corrupted, moving it to BeginPlay now won't help. Though you could try (in BeginPlay) adding
                Code:
                MovementComponent->OnProjectileStop.Clear();
                before re-binding it.
                Clearing and Re-Bounding the delegate inside the BeginPlay() seems to work fine. Even though I still don't understand what's the reason of this mess..... And I would like to know what is definitely the right way to do this.

                Also, I have noticed that with my Grenade (which explodes after a certain ammount of time) the AddDynamicOnImpact() function is called twice.

                1) The first one is called as soon as my Grenade hits the wall. Which is right, because the Projectile hits something and the delegate gets triggered.

                2) The second one is called before the Grenade explodes. But it's strange since the Grenade has already collided with the wall. Why should the function be called twice? And, more importantly, why the function gets called again after some time and not instantly?

                What I have noticed, though, is that while the AddDynamicOnImpact() delegate is called twice, the OnImpact() function IS NOT.

                This because the OnImpact() function has a Role == ROLE_Authority check.

                The first time the delegate AddDynamicOnImpact() is triggered, it is able to execute OnImpact().
                The second time, however, it isn't because it doesn't pass the Authority check.

                So what's going on here?
                Last edited by gedamial; 12-23-2016, 11:03 AM.

                Comment


                  #9
                  Are you running in multiplayer? Sounds like it's just being called once for server, once for client, and the client doesn't pass the authority check. Which is as it should be. I don't know the details of when ProjectileStop is supposed to fire, I've never used it.

                  Anyway, sounds like the original issue probably is a corrupted delegate, same as I had. You can leave the Clear call there and it should be fine, though if you want to resolve it properly the easiest way would be to recreate your blueprint from scratch, if that's feasible.

                  Comment


                    #10
                    Originally posted by kamrann View Post
                    Are you running in multiplayer? Sounds like it's just being called once for server, once for client, and the client doesn't pass the authority check. Which is as it should be. I don't know the details of when ProjectileStop is supposed to fire, I've never used it.
                    I agree with you that the function has to be called twice, since there is a multiplayer context.

                    But they are not called instantly twice. The server-version is called first... after a while the client-version.

                    I need to know more about this. I can't continue the development of my game with these holes in the code.

                    Anyway, sounds like the original issue probably is a corrupted delegate, same as I had. You can leave the Clear call there and it should be fine, though if you want to resolve it properly the easiest way would be to recreate your blueprint from scratch, if that's feasible.[/QUOTE]

                    What would you do if you were me?
                    Which delegate would you use (always related to ProjectileStop)?
                    For which reason rebuilding the Blueprint could be useful?

                    I can't always rebuild Blueprints...

                    Comment


                      #11
                      Client always lags behind server. If you're talking multiple seconds afterwards, then maybe something else is wrong though.

                      The corrupted delegate binding is stored in the blueprint. So if you create a new blueprint based on the same C++ class, which now only binds the delegate in BeginPlay, it shouldn't have the issue and should work even if you remove the .Clear() call. If you make a habit of binding delegates in BeginPlay rather than a constructor, then you shouldn't run into this again so you wouldn't need to rebuild blueprints regularly.

                      Just to be clear though - I don't think you did anything wrong at all, I think it's just a UE4 bug that a delegate can get corrupted in this way.

                      Comment


                        #12
                        Originally posted by kamrann View Post
                        Client always lags behind server. If you're talking multiple seconds afterwards, then maybe something else is wrong though.
                        Yes, it takes multiple seconds afterwards

                        Originally posted by kamrann View Post
                        The corrupted delegate binding is stored in the blueprint. So if you create a new blueprint based on the same C++ class, which now only binds the delegate in BeginPlay, it shouldn't have the issue and should work even if you remove the .Clear() call. If you make a habit of binding delegates in BeginPlay rather than a constructor, then you shouldn't run into this again so you wouldn't need to rebuild blueprints regularly.
                        I deleted the .Clear() from the BeginPlay() and created another Blueprint.

                        The "fresh new" Blueprint works well even without the .Clear(), whereas the old one used to give problems.

                        BUT................. the AddDynamicOnImpact() function is still called twice with a gap of some seconds between the two calls. WHY? what the hell is going on...


                        [off topic]

                        Originally posted by kamrann View Post
                        Just to be clear though - I don't think you did anything wrong at all, I think it's just a UE4 bug that a delegate can get corrupted in this way.
                        OOOOOH WELL, what can I say?

                        It's been two years and almost all the issues I've had with this Engine were due to Engine bugs.

                        I'm pretty tired of fighting against Engine bugs, instead of fighting against MY bugs
                        I'm tired of remaking Blueprints from scratch for every freakin' thing!

                        I opened a discussion here https://forums.unrealengine.com/show...light=gedamial

                        I don't know how big companies can deal with a so bugged engine...

                        Comment


                          #13
                          Most of the time that I have a really weird bug, it's actually my error, but it's in a place that I wouldn't even think is related.

                          In this case, I'd take a quick pass along every class to see if you forgot a Super call in any overrode method or constructor (especially GetLifetimeReplicatedProps and major events like BeginPlay!) to see if you missed one. That could be silently blocking some of Epic's back-end code from running, which causes weird errors in other, seemingly-unrelated places. Pay close attention to important classes, like your subclass of GameState.
                          Last edited by ScottMichaud; 12-23-2016, 01:08 PM.

                          Comment


                            #14
                            Originally posted by ScottMichaud View Post
                            Most of the time that I have a really weird bug, it's actually my error, but it's in a place that I wouldn't even think is related.

                            In this case, I'd take a quick pass along every class to see if you forgot a Super call in any overrode method or constructor (especially GetLifetimeReplicatedProps and major events like BeginPlay!) to see if you missed one.
                            Calling the Super() is a habit for me. And yes, I checked. I never forgot it.

                            I'm so frustrated I can't figure out why it calls the function with that delay.....

                            Comment


                              #15
                              You are inside Visual Studio. You have all the debugging tools you need to figure this out!

                              First, after you bind the initial delegate, set a data breakpoint on the actual data structure of the delegate. This will show you if something "corrupts" the data.
                              Second, inside each call, follow the call chain up the stack, looking at the code in each place. You should be able to find the kind of code that calls the function in each case, and from that figure out why it's being called.
                              (If the "source" of the call ends up being indirected through some asynchronous event, this requires more patience to track down, but it's still totally possible.)
                              Note that, on the call stack, you will see which delegate is actually being called to generate your function call (this may go several levels.) You can thus put a breakpoint on where those delegates are set, to see where they get initialized.

                              The computer is 100% deterministic. It's doing what it's doing for a reason. The debugger allows you to inspect everything it is doing, so you can use that to work your way backwards to the source. What you need is the time and determination to do that.

                              Comment

                              Working...
                              X