• Happy Holidays Guest!

    We want to announce that we will be working at reduced staffing for the holidays. Specifically Monday the 23rd until Jan 2nd.

    This will affect approval queue times and responses to support tickets. Please adjust your plans accordingly and enjoy yourselves this holiday season!

  • Hi Guest!

    Please be aware that we have released a critical security patch for VaM. We strongly recommend updating to version 1.22.0.7 using the VaM_Updater found in your installation folder.

    Details about the security patch can be found here.
Timeline
I'm so confused! :D So, what Audio Link does is actually continuously set the time of Timeline to be the same as the audio link... so it _should_ work perfectly. But you say even that doesn't :| And it works fine with 275? I think this used the "old" implementation of real time, which was notoriously broken. So.... I'm very confused. I need to make something to help diagnose that issue... like play a "beep" every second so you can _hear_ the Timeline timing. I feel like maybe it's simply because Unity's audio introduces a delay that is not counted in the play time of the audio source or something like that... I feel like this whole issue actually has nothing to do with Timeline, and is with Unity's audio: https://forum.unity.com/threads/sound-is-played-with-a-delay.541693/

Still... I'd like to figure this one out eventually.
 
I'm so confused! :D So, what Audio Link does is actually continuously set the time of Timeline to be the same as the audio link... so it _should_ work perfectly. But you say even that doesn't :| And it works fine with 275? I think this used the "old" implementation of real time, which was notoriously broken. So.... I'm very confused. I need to make something to help diagnose that issue... like play a "beep" every second so you can _hear_ the Timeline timing. I feel like maybe it's simply because Unity's audio introduces a delay that is not counted in the play time of the audio source or something like that... I feel like this whole issue actually has nothing to do with Timeline, and is with Unity's audio: https://forum.unity.com/threads/sound-is-played-with-a-delay.541693/

Still... I'd like to figure this one out eventually.
I will get cracking on it. My new scene is up, so I'll dedicate some time to doing some real tests for it. Timeline is my whole world, so I'm willing to do whatever I can to lend a hand to make it the best it can be!
 
Hey AcidBubbles,
thanks for this crucial plugin. I'm starting to fiddle around with it and it's awesome! But i encounterd two downsides I'd love to have:
1. Is it possible to start a random animation from a segment by trigger? And i mean not by transitioning. I have several looping anims that are not supposed to transition own their own, and i want to switch to another one randomly by trigger (i.e. VAMStory), either by a blend or pose snap. The only way to init a random pose seems to be via transition after x seconds, which is not what i want. Am I missing something?
2. I'm working a lot with controller states set to off or locked, be it position, rotation or both. Mainly because position of and rotation on results in a naturally swinging movement of the limbs. But in another, following anim i like the controller beeing on (or locked) again. It seems the controller state isn't accessible as a target, so that i could set it to the value i need for the next anim. Guess it's because it is not a float value, but an enum. I know, if i snap to the next anim via pose this isn't an issue, but it would be great for blending anims. I know, too, that this isn't exactl trivial, because if you'd just set it to off after a locked or on state, you'd get unsatisfying results, and the other way round, too. In the first case you'd had to start setting it to on, and then slowly increase the spring from 0 to the desired value. This could either be handled by TImeline automatically (I've already set up the logic for that in an unreleased plugin if you're interested), or be done by the user, since the spring is available as a target. If only we had the controller state to our hands...

Aside from these (tiny) complaints, you've done an outstanding job with this masterpiece!
Cheesy
 
Last edited:
@CheesyFX Hi! Thanks :D

1. You can use the trigger "Play Prefix/*" which will show up if your animations you want to randomize have the same prefix (i.e. something with a slash). When you play that animation, the whole segment will also switch, and other layers will play at their first animations, unless you use animations set (check the wiki for this, animation sets are more advanced but you shouldn't need that). Also, note that you might want to disable the "Preserve Loop" toggle if you want the animation to switch immediately, otherwise it'll wait to smoothly switch loops while maintaining the coherence of animations.
2. You really have to use Timeline's pose system for that. It won't blend though, but it will be easy and always work (check my scene The Boss, I also use VamOverlays to nicely transition things). If you do want to do that, you can reduce the weight of the controllers you don't want animated and use triggers to change the controller state. Controller weight can be found in the right panel of Targets when you expand it. Timeline also has Controller Weight triggers that you can animate (yes, Timeline can animate itself!) if you prefer.

Feel free to complain (actually this was asking for help, not complaining, which is perfectly fine!)
 
Also, note that you might want to disable the "Preserve Loop" toggle if you want the animation to switch immediately
Ha, I have never known what that toggle was for, and I have been through the wiki for things several times. Good to know!
 
@Acid Bubbles Thanks for your detailed answer!
1. Thats exacltly what i needed, thanks for the hint.
2. Your right, i can switch the states via trigger-track. It's tedious, involving a lot of triggers, and i have to think ahead which anims are supposed to transition to or follow the ones with different controller states, but it's doable. But if all anims are supposed to play randomly, then all i can do is to put all triggers on all anims, which isn't exactly efficient or convenient. I still think it would be awesome if you could implement a smooth transition between the states. As i said above, i already have a fairly reliable logic for that, so please write me a message if you are willing to evolve timeline in this regard. The main problem i see is integrating non-float targets into the system. For my needs it would be sufficient if they were separate from the usual targets, allowing the user to set them only once as an attribute of the animation. The blending could then be done automatically during the specified transition time, if necessary. The states could also be restricted to On, Off and Locked, since the parenting is already handled separately from vanilla VAM. This makes the logik a lot easier.
Greetings
Cheesy
 
Hey AcidBubbles,

I've had lots of fun using your plugin lately, but i also had a hard time to accomplish some things i have in mind. Mainly because there seems to only be limited trigger/action functionality.
Is there a way to force a pose snap when selecting a pose via action? And no, i don't want to toggle "Apply pose on transition" because that would apply to all transitions leading to this pose. Let's say I have a smooth transition B>A, but C>A isn't possible (or not implemented yet). So if I'm on C I want to snap, otherwise not. The only solution seems to be to have 2 copies of A, one with "Apply pose on transition" and one without. I also tried the different "Stop" actions prior to triggering the anim (to mimic the plugin UI behaviour), but with no success. I also noticed that the stop action didn't always act on all persons.
I just saw that there is a "apply pose" action exposed to Keybindings. So you probably only had to register the associated action.

About the "play" action: Is it correct that it acts like the "play all" button in the UI? Is there a way to only trigger "play" or switch from "play all" to just "play" via trigger? The reason is, that I have multiple main poses, each with different sub poses. The sub poses are chained randomly if "play all" is active. Now I want the user to be able to disable this feature and keep the current sub pose for some time. Essentially like pressing the middle play button in the UI.

About the "next" feature:
Why is there no "Next Segment" action? I find the "Next Animation" a bit useless (for my workflow), because with "next", i want to jump or transition to the next main pose, not the next pose in the list. But how I am supposed to order my animations to accomplish that? Say I'm on anim A2 and by the press of a button i want to jump to the next main pose B0. But the next in the list is usually A3. Even if I order them like A0,B0,C0 followed by all sub poses, the result would be messed up. I know i could create a button triggering B0 directly, and if pressed, hide it and show a new one triggering C0 and so on. But i really want to avoid that. I hate navigating through that trigger hell.
If there was a "Next Segment" I could separate all main poses to different segments and order them correctly, so that "Next" has an actual meaning to it.

Right now I'm writing a scene manager plugin to drive timeline, so that i only have to use one "Next" and "Previous" button. The simpe plugin tracks the current main pose and also takes care of the possible transitions. But i want my plugin to decide, if there should be smooth transition or a pose snap, depending if a transition is available. But that does not seem to be possible without having lots of duplicated anims (see above).
It also would be nice if I could extract info about the containing animations. Iteration through the list of Play actions would be possible, but only if i used unique names across all segments. Sadly, if i have A in different segments i get only one "Play A" action and no reference from which segment it originates. Would you generally recommend naming anims with a prefix, like "seg1.A" etc?

I'm sorry, I know I'm complaining a lot. I really love your work and you owe me nothing. But maybe you find some of my thoughts useful for future updates. The past weeks i had many other ideas how timeline could be further improved. Let me know if you're interested!

Cheesy
 
@CheesyFX I see the problem, and yeah right now you can do that by having two animations. You could however have something like Layer A with Anim WP (no pose) and Anim NP (pose), and Layer B with Anim 1 (your actual animation) and have them all share the same animation set (in Edit or Sequence, I'm not sure right now). Then if you play WP or NP, it'll always play Anim 1 with it, so you don't have to clone the whole animation. But yeah it's starting to get complicated :D

There _should_ be a segment option in the play next menu. But keep in mind, if you switch to the animation of another segment, it will switch the whole segment anyway.

And I don't see that as complaining, Timeline's pretty complex, and I know there's a _ton_ of things I could do, sadly I didn't get tons of help (understandably, it's not easy to contribute to it) so I'm doing my best to help find workarounds.

If you're courageous, you could also check Scripter or LogicBricks (depending whether you're comfortable doing scripting) to drive the logic, though usually I can make things work with just Timeline. For example, could have Anim 1, Anim 1 -> 2, Anim 2 -> 1, Anim 2 so Next / Prev have transition animations with their own triggers and logic.
 
@Acid Bubbles No, I have some experience in scripting, so I have no problem in writing my own plugin driving the animations. The problem is the limited access we have from a third party plugin. But after digging through your code i have found a solution for the pose snapping problem: I have to call "Stop", then set the desired animation via the registered JSONStorableStringChooser called "Animation", followed by a "Play" call :)

But I'm a bit curious why i can't get the current value from the StringChooser. GetStringChooserParamValue("Animation") always yieds an empty string. Same if i do GetStringChooserJSONParam("Animation").val. Does it get reset to "" directly after setting it (without callback of course)?
But i can set it, and thats what i primarily need. I can keep track of the currently playing animation myself.

Now there is only the problem with the switch from "Play All" to just "Play".
 
The Animation drop down is only there for backward compatibility... it's a "set only" value. There were talks of adding an API on Timeline for more complex cases but there were always simpler workarounds.

For the Play All, technically Play is just while you make the animation. You can however make sure animations are not shared on layers and have a "noop" animation on each layer to achieve a similar result.
 
@Acid Bubbles Ok, then please don't remove it in future updates. My plugin relies heavily on it.
One thing i would find very useful: An option to sync renaming on other atoms (same name rule). Right now i have to repeat renaming on all other atoms to not break synchronization. Or is that feature already available and i missed it?
 
I don't plan on making big breaking changes at this point, it would be suicide ;) There's a sync feature but it's not super reliable, and renaming has to be done manually. I didn't make it automatic because you would have no way to "unlink" animations, and I didn't add a dedicated button, so... yeah, planning helps in that case.
 
Ok, i understand that it's not a priority for you. It's not strictly necessary if you plan ahead.
But it would be useful to me. And if there was a toggle for the auto rename feature (options), then one would only have to toggle it off temporarily to unlink.
Or otherwise: I would keep that feature off by default, and if the user decides to rename a bunch of linked anims, he can toggle it on.
 
Last edited:
I still can't find how to import animation to the current segment rather than create a new segment. Or something like moving one animation from one segment to another segment, can somebody tell me how to do that?

Thanks!
 
@Wxy_332 You should go to the create segment screen, then press "convert anim to segment". This creates a new segment containing the current anim. I would also like a feature to move an anim to another segment, but that doesn't seem to be possible. Probably because there could be a target mismatch between the two segments. The algorithm would have to check which targets are missing and add them automatically.

If you really need it, you can try editing the scene.json directly. But don't forget to make a backup first ;)
 
@Acid Bubbles Forget about the renaming thing. It's not that important. I can still edit the .json by search and replace.
But there are 3 things i really, really would like to be implemented because I'm stuck with my project and can't do what i have in mind:
1. A way to retrieve the currently playing animation as a JSONStorableString I can get the value of.
2. A way to toggle between "play" and "play all" via script, i.e. prevent auto sequencing.
3. This probably requires a bit more work, but I miss a feature to exclude all animations from randomized sequencing whose names contain a specific string.
I'm assuming the randomizer iterates trough the list of all anims and selects the ones containing the specified group identifier, i.e. "anims/". Maybe you could add a text input field so one could set an additional string that should be excluded from the said list. like ">".

Background for 3:
I have poses with different animations that should be called randomly, i.e. A/00, A/01, B/00, B/01. And there are transitions between the poses, like A/>B and B/>A, which should also have the possibility to get selected randomly, hence the group identifiers. I want the transition A/>B beeing sequenced by B/* to have variety. But then the problem is, that A/>B can be directly followed by B/>A, leading to an unnatural in and out behaviour. So, I'd like to set the sequencing of A/>B to B/*, but exclude all transitions (containing ">").

If you don't have the time for this, I'm tempted to add this to your code myself. Would you grant me permission to provide the modified version with my scene? I could also send you the files for inspection. If it's all right you could make an official minor update of it, too.
Could you please point me to the file containing the definition of the animation dropdown and the play buttons in the UI? This should be all i need for investigating further (for 1 and 2). I simply could not find them, there are so many files :O

Thanks!
 
Last edited:
@Wxy_332 You can only import animations if they are compatible with a segment, meaning they have the exact same list of animatables targets. Otherwise you can import in a new temporary segment, and then copy and paste the keyframes (in More, Bulk) that you want.
 
@CheesyFX I was asked a few times for a "current animation storable", I think I have found a good way to do it. Can't say when I'll have time, but at least I have a solution. But please don't wait on me, I just don't have enough arms to do everything I have to do.

Preventing sequencing would be extremely tricky, so that will not happen, even if there are good reasons for it.

As for "anything but", this is also tricky in terms of UI...

If you want to contribute, I greatly encourage you to do so, I hoped for help for a long time but not many people are ready to invest the time :) You can checkout the code here: https://github.com/acidbubbles/vam-timeline and provide pull requests, I can try and point you in the right direction. However I don't want custom Timeline versions around, even though I do understand it'd make things easier for you, it'll be hell for me as people will start referencing custom versions without being aware of it, and contacting me about issues I will not be able to understand because I won't have the right information. So please, don't do that.

- This is the sequence drop down: https://github.com/acidbubbles/vam-timeline/blob/master/src/UI/Screens/SequencingScreen.cs#L96
- This is where the scheduling happens: https://github.com/acidbubbles/vam-...s/Animations/AtomAnimation.Sequencing.cs#L149

The project is fairly complex, so don't expect a quick fix, but if you're ready to iterate a few times to get it right, I'll be happy to support you!
 
@Acid Bubbles Thanks, I'll definitely try to contribute. If i have something in mind i want to make it possible, no mather the costs :)

"current animation storable"
Yeah, you already have a member called "current". Why not simply ask for it's name attribute (assuming the anim has one)? But I could not grasp what it points to if there's currently a blend happening. Also, I'm not sure yet what I want the getter to output in that case...

Preventing sequencing would be extremely tricky
Hmm, i thought i'd just register an Action executing the callback of the "play" button, maybe preceeded by a "stop" call. Because that does what i need. But maybe thats to naive, i have to get a better insight of the project. But wait: Is the problem tied to the fact that the stop and play callbacks act on the animation selected in the UI and not the one currently playing? Then maybe we have to select the currently playing anim first (by setting the Animation JSON). Seems i have to look into setting up a getter for the current anim first (if you're not fast enough ;)).

As for "anything but", this is also tricky in terms of UI...
Again, hmmm. I don't get why the UI is the problem. I'd just set up a 1 line text input field below the "Play Next" chooser. You already have to scroll in that screen, so there is no beautiful arrangement getting "destroyed" by that.

I totally understand that you don't want to mess with custom versions. I won't release/package anything without your approval.

The next weeks will be a bit stressful for me, but I'll come back to you when I have a question or something to show. Thanks for your help, and of course your awesome plugin :)
 
Last edited:
If you want to try doing the "getter", you should publish a storable string chooser for every segment and layer, for which the value would be updated (in AtomPlugin.cs). There should be similar code for updating speed storables you could look at.
 
Hey! I'm slowly digging deeper into your code, but there are some questions arising. What is the best way to communicate to you? Do you read your private messages? Or are you on discord? If so, am I allowed to add you there?

I want the names of the getters to be prefixed by their segment name, like "seg1.layer1" to make them unique, regardless if 2 segments hold layers of the same name. This once more made me think about why the heck are clip names not internally unique? Is there a deeper reason for it? If the user does not set up unique names across all segments and all layers, it is impossible to trigger (or change the speed of) a specific animation. Because the list 'animationNames' will contain duplicates, so that only the last registered action of that name is available.
Why didn't you set up a displayName (the one shown and editable in the UI) and an internal name, which is prefixed by <segmentName>.<layerName>. For the registered actions this name could then be used to make it unique (although the names could be very long).
Specifically for my usecase this caused a lot of headaches, because I want to be able to trigger almost any anim from my external plugin, so i had to manually add a .<segmentIdentifier> to each relevant anim to make them unique.
I could possibly make this change, but 1. it would break all scenes which depend on the action names to trigger and 2. it would be hard for me to track down each and every dependency of the names.
Either way, I try to make this new feature independent of the naming scheme.

Second question: What is the best way to document my changes, so that you can inspect them? I'm working with Rider and I don't have much experience with Git, aside from browsing and downloading some code here and there.
 
Last edited:
I just don't get your object structure. So far i have a method CreateAndRegisterLayerStorables, which should take a segment (or its id, or its name) and register the getters for each layer it contains. But I'm missing a connection between the segmentName and the segment itself, or its index.
animation.index.segmentIds seems to hold some arbitrary numbers that do not correspond to the index the segments name has in animation.index.segmentNames. After init (reload) animation.index.segmentIds only has one entry '11', altough there is only one segment. So, if i pass this id to my method, i can't get the name of the segment, because segmentNames[id] yields an 'index out of range' error. And if i pass the name of the segment, I can't find a way to get the corresponding IndexedSegment to iterate over its layers, because there is only a Dict mapping the segments by their id.
Why doesn't the IndexedSegment class contain a member holding its name? Could i add one, or is there anything I'm not aware of?

Again, I want my method to not blindly iterate over all layers in the scene, I want it to also have access to the name of the segment the layers belong to, to add a prefix to the storables names (to make them unique).
 
Last edited:
@CheesyFX You can reach out on Discord, I have my own Discord (link in all of my plugins), feel free to ping me there. It's often easier to have quick discussions there. And.... yeah, Timeline is _complex_ but also started as a cool proof of concept. I tried to keep refactoring it, but I'm not keeping up lol. Still, there's a logic despite it being far from perfect. Ask away and I'll point out the way things are built, you don't have to figure it out yourself :D

- Unique: There's qualifiedAnimationName, qualifiedLayerName, etc. which are namespace (unique across all animations). There's also an index (animation.index) to quickly access them without having to do string comparisons.
- The idea of sharing animation names across layers is to have cross-layer animations, so the goal is to have them in sync, at least as much as possible. So updating the speed of Anim 1 will update it for all layers.
- Git: I strongly suggest you learn the basics of making PRs in GitHub, this way I can easily contribute, provide feedback, etc. It was created for this purpose, so it's worth learning, and GitHub really has great tutorials to help you with it.
- By the way, you can make "ugly proof of concepts" first, so we can play with the ideas, before trying to make it clean. If the idea is clear, I can also help by writing some of the code for you, or at least pieces of it to help you navigate my mess.
- About the IDs, yeah strings are expensive, so I'm computing a int representation of names so I can look them up efficiently (yeah Timeline's complicated in part because it is very performance-oriented). That makes things harder to follow. Normally you _always_ receive a string, and find it in maps using it's ID, but you should never have to find a name from an ID, if you do you can load the animation from the map.

The way I'd do it, is when an animation is created, removed or rename (there's an event for that), rebuild a list of all layers to create a storable for it, and when an animation starts, find the matching storable from a map (using the ID, not the name, for perf) and update it's value.

Feel free to continue the conversation here, on GitHub or on Discord ;)
 
Back
Top Bottom