I have a Scene Component derived C++ class, which has a property that can be changed in a level sequence:
float MyProperty = 0.0f;
Now, the problem is, I need to get notified when the value of MyProperty has been changed by a level sequence. I first tried overriding the PostEditChangeProperty function, but that doesn’t seem to get called when a level sequence is in charge of changing the value. I then dug a bit deeper and found out that there is a function PostInterpChange, I was sure that this was the function I needed, but that function didn’t get called either.
I also tried finding information from the engine code, like the UPointLightComponent that is getting notified when for instance the Intensity property is changed in a sequence. At first it looked like the UPointLightComponent was using the PostInterpChange function, but when I tried to confirm that by putting a UE_LOG there, it proved to be not working there either.
So there clearly is a way to achieve my goal, but I’m just not able to figure out how. Perhaps I need some boilerplate code somewhere or the engine is just bugged (which I don’t really think is the case).
A cheap trick is to use the replication callback.
Tag your variable as this:
UPROPERTY(ReplicatedUsing = OnRep_YourUFunction)
Implement OnRep_YourUFunction as a UFUNCTION.
This will be called anytime YourVar change value.
You also need to add this to your .cpp:
void UYourCLass::GetLifetimeReplicatedProps(TArray& OutLifetimeProps)const
Out of curiosity, how are you setting the value of this component property with sequencer? Through an event? If so then it might just make sense to create a function “SetMyPropertyValue(float NewValue)” or something like that, and do whatever it is you want to do with the new value in there.
That would work pretty well in a single player scenario, the problem being that, the game I’m making is a multiplayer one. The level sequence is going to run on both the client and the server, and replicating the properties of the sequence could break something + it would use the network bandwidth without actually needing.
I am just keyframing it as you would do for a Scene Component’s transform or a Point Light Component’s intensity. Basic sequencer stuff.
Ok, here’s what I would do with the information given. Have your tick event in the component check for a change in the value. If it changed, take action. Does that make sense?
If the Actor you wanna notify is already placed in the level you could add it to the Sequencer, then add an Event>Trigger to its Track.
This wouldn’t work sicne I want the event also to be called at edit time, end Tick only triggers at runtime. I think I should do more testing with the PostInterpChange function (like testing different engine versions), since it has been documented to do pretty much what I am trying to achieve.
I think that would technically work, but because its a float value thet gets interpolated between the keyframes, I would have to add a trigger event on every frame of the sequence which could get really messy and annoying.
Ok, now I’m intrigued…so during edit playback the sequencer doesn’t simulate tick on the actors/components which are keyframed…hmmmm. If you absolutely need it to show during editing then I’ve hit the end of my knowledge rope. I can’t escape the feeling that I have to know how this works even though it’s not an issue I’ve faced
I’m not in front of UE at the moment so I can’t play around and test some ideas out. I’ll do so this evening assuming you haven’t already figured this out.
Yeah, getting notified of the value changing is pretty vital, since the whole point of the component is to get used in a level sequence. I maybe should have clarified this earlier but the component is a custom mesh component whiches shape can be controlled by a few properties.
I think I could get some answers by reading more engine code but I haven’t been able to access my computer today.
Ok, so I think this runs deep but I believe it’s related to the sections in PointLightComponent.h and cpp that have the WITH_EDITOR makers…
…and by “deep” I mean there are a couple levels of inheritance on this component (like 4 or 5) before you get to the base USceneComponent and each one has some level of WITH_EDITOR functionality. I’ll likely poke a bit more at this over the weekend as again, I’m intrigued.
Yeah it’s a bit hard to try to figure this out because of the ‘deepness’ of the UPointLightComponent hierarchy. But as we can see there in your screen shot the PostInterpChange function is clearly ment to do something related of a member variable changing (it literally has a parameter PropertyThatChanged and in the function it is comparing that parameter to a member variable). On top of all that, the function isn’t in a #if WITH_EDITOR block, so it exists both in an editor build as well as in a game build.
Now that I think it, I probably shoult test if that function even gets called in the engine code.
I’m not in front of the code at the moment but looking at the screenshots and thinking things through here are some thoughts I have…
- If you want the change to happen in editor you’re going to need to implement those WITH_EDITOR functions. Understanding of course that whatever you put there will not be packaged in a build so if you need the functionality in game then don’t put it there.
- I believe the key to making the update occur is the MarkRenderStateDirty() function call that you see in PostInterpChange. That likely causes a chain of events which will eventually cause the viewport to update.
The outstanding question of course is what’s happening in the parent versions of the WITH_EDITOR functions? As you can see they are being called “Super::Post…” after the point light component does point light specific stuff. This means you might have to dig one layer at a time and make sure there’s nothing there which might aid this effort. I suspect there’s not. Like I said in item 2, I believe the key to making it update in the viewport is the call to markRenderStateDirty()…which they only set if the LightFallofExponent gets changed…which does in fact get changed in PostEditChangeProperty…which is allowed to be changed according to CanEditChange. If I had to guess I would say that, when setting a UObject variable, the editor calls CanEditChange to see if the variable can be edited…if it can then it edits it (changes its value) and then calls PostEditChangeProperty to give you a chance to do something. It then follows that some chain of events will lead to PostInterChange being called allowing you to mark the render state as dirty.
Ugghh…I wish I were in front of the editor at the moment
Sorry I haven’t been able to answer more quickly.
I don’t think that the other “Post…” functions play a role in getting the PostInterpChange called. I tested implemrnting all the “Post…” functions to see what each of them do. Most of them worked just as I expected, and the ones that have been implemwnted in a WITH_EDITOR block of cource weren’t called in game. I also noticed that the PostInterpChange doesn’t even get called in a non-editor game.
The MarkRenderStateDirty was a good mention but it doesn’t seem to be the problem I have, since even UE_LOGs that I put in the PostInterpChange aren’t showing.
I’m starting to think that the PostInterpChange isn’t even the key of getting notified. One thing I should test when I get back to my computer is to directly inherit the UPointLightComponent and override the PostInterpChange there. If even that won’t get called, I’m pretty sure the PostInterpChange is for a whole different purpose (which would be pretty weird since the documentarion leads to understand it being just for what we think).
Anyhow thanks for helping me solve this problem. If we are not going to find the answer, I’m gonna give you the solution mark.
I haven’t had the cycles between my development efforts to really test thoroughly so I’ll throw out a bit of a hail mary and maybe that will spark something…
I realize this was a question on the c++ side of the house but I figured I’d start by trying to do it in BP. I’m aware that there’s an “Expose to cinematics” checkbox available under the details of a BP variable. I created a simple actor with a static mesh component. I added a float variable and checked this flag along with the “Instance Editable” flag. From there, under the “Class Settings” of the actor there’s another special flag called “Run construction script in sequencer”…check that. Now, under the construction script of the actor I used the value of that variable to set the scale of the static mesh component. I could then simply add the aforementioned actor variable as a track to the sequencer and have it set and update in editor. Here’s a quick video showing it in action…
After that, I attempted to take it one step further by simply creating a subclass of the static mesh component in BP and repeat the same process. I could not get this to work. First, you don’t get a construction script for BP components. Second, while I could see the variable change within the editor during playback, I could not get it to take effect. This might just be another one of those “you can do it in c++ but no in bp” deals so I didn’t push too hard down that path.
Anyway, maybe this offers another avenue of approach…or maybe it adds a layer that is not wanted. One of the major drawbacks I noticed is that, of course, since the construction script is run once during actual play, this type of sequencing only seems to be valuable if playing the movie from the sequencer (so in editor). You you try to actually play the level it of course does not work.
More food for thought…I don’t know if you should be expecting to get print outs while playing/scrubbing from the sequencer. As a simple test I added an event to the sequencer which prints to both the screen and the log…neither come through when playing from the sequencer…only during play.
At any rate, best of luck going forward. I’ll likely poke at this on the side over the next couple of days but I’m sure you need to get moving. If I come up with anything more in line with the question I’ll post for future onlookers.
Ok at this point I have tested literally everything, no answers, no workarounds…
In the PointLightComponent class they are probably using some kind of magic to get it working or maybe getting notified of a sequencer change isn’t even a feature in Unreal Engine, and PointLightComponent and a few other classes are just hard coded into the Level Sequencers code to work how they do. What feels like the weirdest thing to me is that no one else in the internet seems to have had this same problem, even tho I don’t see many cases where you would expose a property to a sequence but wouldn’t need to get notified of it changing. Maybe people just don’t expose to the sequencer at all ¯_(ツ)_/¯
I didn’t even know that in blueprint there was that “Run construction script in sequencer”, but it only seems to be a blueprint feature, no sings of any C++ counterpart existing (usually it’s the other way around but not in here I guess), so that won’t help me too much.
At this point I pretty much have three options:
- I could make it so that you can’t see the changes to the properties at all on edit time, only at runtime, which sounds like a very annoying tool to use
- I could try to Implement a whole new sequencing tool for that component: make a CallInEditor function for keyframing a state, and save the state to a data structure, and also have a time for each keyframe, and also have a few more CallInEditor functions for playing and stopping it and etc…
- I could just abandon the whole project and do something else with my life
The second option is probably what I’m going to try to do, but my motivation for this has kinda dropped already so at the end I may just end up giving up with this
And finally, I really want to thank you @gh0stfase1 for helping me all along with this problem, I would’ve taken me much longer to make all these discoveries without any help
Hi guys, I have exactly the same problem at hand… the sequencer changes the value of the variable but doesn’t change the value of the object actor… any of you found a solution to make this change happen in the editor instead of at time of execution?
Sadly I didn’t find a good solution. The fact that the object doesn’t get notified by the sequencer change in any way might also be a bug maybe? If you find any solutions or even clues of how this could be achieved, please let us know.
Level Sequence has a blueprint script, on which you can notify event from it to others, hope this will help