The event timeline allows events to be triggered at specific times during an animation. These events can be used for anything at runtime. For example, spawning particles or playing a sound.
To use events, first create a new event under the Events node. In setup mode, you can set up an int, float, and string value for the event, if needed. In animate mode, you can click the key dot in the tree next to the event to set an event key at the current timeline position. You can also change the int, float, and string value before setting a key, which allows you to have per key values if the setup mode event values are not sufficient for your needs.
At runtime, when an animation is applied (or mixed) the parameters have changed. It used to be:
apply (Skeleton skeleton, float time, boolean loop)
mix (Skeleton skeleton, float time, boolean loop, float alpha)
Now it is:
apply (Skeleton skeleton, float lastTime, float time, boolean loop, List<Event> events)
mix (Skeleton skeleton, float lastTime, float time, boolean loop, List<Event> events, float alpha)
"lastTime" and "events" are new. Any events between "lastTime" and "time" will be added to the events list, so you probably want to clear the list before calling these methods. You can then iterate the events, inspect their name, int, float, and string values, and take whatever action you like. If you don't care about events you can pass a very high value for "lastTime" and null for "events" (since a very high "lastTime" means no events will ever be triggered).
If using AnimationState, then nothing changes, internally it does this for you. How the AnimationState lets you know about events is runtime specific. Some runtimes use a listener, others may return the events list. Only the current animation fires events, no events are fired from the old animation even if it is being mixed.