#ApplyRootForce Callback Question
1 messages ยท Page 1 of 1 (latest)
i took it to a thread so we dont clog up the chat if thats ok
these are the only files from it so i guess he maybe overrode something from unreals stuff
so it will be somewhere in RootMovementLibrary
this is a search for the function
what are all the functions available in RootMovementLibrary.h
AsyncRootMovement.h?
yah thats the one
oh so here is the on complete and fail nodes i presume
so the way you use AsyncActions like this one here, is instead of just calling the function,
the function returns you an Object (AsyncAction*).
you can bind to the delegates with the object that is returned, and you can keep the Object around to cancel it or do whatever.
and when you are ready for it to run you call Activate on it
sounds complicated but it's like 3-4 steps max
in blueprint the Activate is called automatically for you
it does cause im kinda lost again. are you saying i dont call the function in my player controller class like i did?
lemme review your original comment
instead of URootMovementLibrary::ApplyRootMotionConstantForce( ... );
you do those steps in that image
this correct?
i put the async stuff?
it's still calling the Synchronous function in the image
first step, you call it like this:
auto* AsyncAction = UAsyncRootMovement::AsyncRootMovement( ... );
yup, once you fix the parameters first step is good
alternatively can i declare an asyncaction in the header or is it better to just make a new one each time?
kinda a tangent
you need to create a single async action for each time you call it, the resulting object "owns" the async call's lifetime. it acts as a lifetime scope for the async call that can exist for multiple frames
the player controller should have access to the World yeah
sorry, WorldContextObject should be this
WorldContextObject should be the UObject that is calling the AsyncAction, so it would be:
UAsyncRootMovement::AsyncRootMovement(this, ... );
i think the only thing trippin me in the parameters is this noe
havent used it before
that's library specific, your going to have to make a call
im not sure its needed i guess i could remove it from the parameter
ah yeah i did that in the original function lol
ok cool parameters are fixed
so now is it making delegates in the header of the player controller?
step 2 creating the UFUNCTIONS that will be bound to the delegates
yeah
you need to match their parameters to the Delegate type
so you need to look at the signature of OnComplete's and OnFail's variable types
the Fmovmentevent?
yeah ctrl+click FMovementEvent to see what parameters it needs
ah here at the top
a unfunction in my player controller class correct?
yup
im following
the player controller:
UFUNCTION()
void OnComplete();
UFUNCTION()
void OnFail();
(not UPROPERTY)
ohhhh
I like to call them ReceiveOnComplete / Receive<Blah> to distinguish it
no worries, we all start somewhere
ive done dynamic delegates in the past with some courses but i took huge hiatus' and forgetten alot of it
so you need to implement those functions... can just leave them empty for now,
and move on to step 3, which is simply to bind them
back where you created the async action
โ๏ธ
you bind them directly in the jump function?
yeah
because it's an AsyncAction, remember the AsyncAction object get's created every time you call it
so it get's bound right there
not like other delegates that get bound in BeginPlay
ahh ok yeah yet another reason i was confused since anytime i bound delegate its was in begin play
ah yeah lol
and it would be bound as an FMovmentEvent right?
it would look like this:
AsyncAction->OnComplete.AddDynamic(this, &ThisClass::ReceiveOnComplete);
oh whoops
hm the OnComplete is inaccessible in a private field. i guess in the async class i need to move it?
doesnt say its in a private field tho i as look
yeezus
that seemed to fix it
if it's private/protected you would need to move it to public yeah
i guess if its not specified its automatically private?
anyways i put it in a public field
class fields are private by default if not specified yeah.
ah ok makes sense then
galloping gophers batman
ok so now i can just put whatever code i want in the ReceivedOnComplete correct and everything is kosher?
step 4 call Activate on the async action right below binding the delegates
that **should **be the last step. but one thing I need to check. does the library author call SetReadyToDestroy();
i dont believe so
so in AsyncRootMovement.h ctrl+f SetReadyToDestroy has no hits?
AsyncRootMovement.cpp I mean not .h
no hits
that's likely a bug.
you need to call SetReadyToDestroy(); after OnComplete and OnFail is called.
or the author didnt put it maybe im not sure
otherwise async action object stay's alive as long as the GameInstance is, I.E. for the duration of the game. even after it's done being used
thats in the same place in my jump?
no you would need to modify AsyncRootMovement.cpp
actually.
Cancel probably calls SetReadyToDestroy
can you check to see what it does
what does Super::Cancel do
alright so you are good to go then

bruh how do i throw you like 10 bucks holy hell
im good
seriously thank you
i never would have figured this out
i always hate asking question in unreal discords cause people have a superiority complex against noobs. again thank you
im actually not sure if the broadcast events complete tho. i added debug messages to the functions but nothing popped up
show the log messages?
no log actually pops up. in debug its saying there is no async actoin
so i breakpointed this
and when i step to the next it goes back and forth between the if
sorry, I could be more specific. I mean the functions you are using to log,
in C++ you need to use
GEngine->AddOnScreenDebugMessage
or UKismetSystemLibrary::PrintString with bPrintToScreen as true
oh a ue log doesnt work?
no
UE_LOG works per se, but it wont add it to your screen
so maybe it is calling
it will only show up in the output log
oh it didnt even show in my output log lemme try the gengine
hm doesnt appear to call
also WorldContext should be this instead of GetWorld
yeah i changed it cause it didnt seem to work so was just shooting in the dark
ah np
it seems like in debug it just gets to eht first line, then steps back in forth between the if call and never goes to activate
but if you thought i was noob my debug skills is dirt
you are likely building Development, which confuses the debugger a bit because the optimized c++ doesn't behave as you would expect.
need to build DebugGame instead
feel free to ping me between messages
wait I can set this thread to have specific notification settings actually ๐cool.
I would set a breakpoint in ReceiveOnComplete, ReceiveOnFailed and UAsyncRootMovement::Cancel.
might be hitting Cancel before broadcasting for some reason
what is the callstack for Cancel
smh i think its frozen
lol
shouldnt it show up if its being called?
i hit escape then stuff poped up
and now the editor is frozen again
oh maybe casue the point hit
normally it would pause then pop the stack
idk i dont know much about debugging yet
๐ค BeginDestroy is being called from EndPlayMap...
when is this getting hit
right when you jump, or are you quitting the editor and then it gets hit?
right
so I would set a breakpoint in UAsyncRootMovement::Activate
the AsyncAction is getting created, the delegates are bound, but the actual action itself doesn't seem to be running (otherwise it would call OnComplete or OnFail). so something may be going wrong in the initial setup.
but if you step through the activate code ( with F10 (Step Over) and F11 (Step Into) ) where does it go?
need to see the code for UAsyncRootMovement::Activate
right... different keybind setups forgot.
well you need to make sure you are getting to this specific line:
so it's getting constructed correctly ๐ค what is OngoingDelay's value
wait now it hit the on complete
maybe cause the delay timer was 0
i changed it to .3
ah, I think 0 has special meaning with TimerManager
nice ๐
so i guess not having an amount other than 0 messed with it i have no idea lol
/**
* Sets a timer to call the given native function at a set interval. If a timer is already set
* for this handle, it will replace the current timer.
*
* @param InOutHandle If the passed-in handle refers to an existing timer, it will be cleared before the new timer is added. A new handle to the new timer is returned in either case.
* @param InObj Object to call the timer function on.
* @param InTimerMethod Method to call when timer fires.
* @param InRate The amount of time (in seconds) between set and firing. If <= 0.f, clears existing timers.
* @param InbLoop true to keep firing at Rate intervals, false to fire only once.
* @param InFirstDelay The time (in seconds) for the first iteration of a looping timer. If < 0.f InRate will be used.
*/
template< class UserClass >
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, typename FTimerDelegate::TMethodPtr< UserClass > InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f)
```
"If <= 0.f, clears existing timers."
yeah Epic has alot of foot guns and idiosyncrasies to learn about
idek know how you go about knowing those kinds of things
i mean i guess over time but to figure them out from scratch
yeesh
tribal knowledge, always ask
asking is not a sign of weakness, it's a sign of not being willing to give up
most of the time its you suck cant you figure it out and look it up 
hopefully its the last time i bug you about this haha
no worries
I'm just as new to different parts of the engine and bug other people on the discord
๐
like im still lost on what exactly and how the async movement is doing the magic but ill leave figuring that out for later lol
literally me just today a while ago:
"
Mk2 โ Today at 11:22 AM
is there a way to tell what ini category a cvar needs to be created under?
(specifically tick.AllowBatchedTicks )
"

