1) Highly encourage your animator to use the Clean Up button. Key Frames - Spine User Guide: Clean Up
It removes unnecessary keys which should make the dopesheet more readable and manageable.
If you don't let your animator know to deliberately avoid these specific keys problems, it will at least minimize the chances of them happening.
2) The Spine Skeleton json has some documentation in case you want to parse it. Spine: JSON export format
Though the problem might be that when you want to switch to binary for release, your postprocessor won't know how to deal with it.
I have a feeling Nate might recommend dealing with this on the Spine project level.
3) You can access the deserialized data through C#, of course. Most of it is internal to the assembly spine-csharp gets compiled into.
But if all you need is to remove a few AttachmentTimelines, it shouldn't be too nasty to handle.
Each Animation object has an ExposedList<Timeline>. This is the list of timelines. Each timeline is the data on keys and where they're placed. If you remove the right AttachmentTimeline from the ExposedList<Timeline>, it should effectively remove all those keys.
Code would look something like this:
void Start () {
var skeletonAnimation = GetComponent<SkeletonAnimation>();
var skeletonData = skeletonAnimation.SkeletonDataAsset.GetSkeletonData(false);
const string cleanupSlotName = "my slot";
int slotIndex = skeletonData.FindSlotIndex(cleanupSlotName);
var animations = skeletonData.Animations;
foreach (var animation in animations) {
RemoveAttachmentTimeline(animation, slotIndex);
}
}
// Modify the Animation object to remove an AttachmentTimeline that handles a given slotIndex.
static void RemoveAttachmentTimeline (Spine.Animation animation, int slotIndex) {
var timelines = animation.Timelines;
int id = -1;
// Find timeline where timeline is attachmentTimeline and attachmentTimeline.SlotIndex == slotIndex
for (int i = 0, n = timelines.Count; i < n; i++) {
var attachmentTimeline = timelines.Items[i] as AttachmentTimeline;
if (attachmentTimeline != null && attachmentTimeline.SlotIndex == slotIndex) {
id = i;
break;
}
}
if (id != -1)
timelines.RemoveAt(id);
}