quisquous / cactbot

FFXIV TypeScript Raiding Overlay
Apache License 2.0
793 stars 378 forks source link

Timeline improvements discussion #5619

Open quisquous opened 1 year ago

quisquous commented 1 year ago

I'm breaking this off from #5577.

Restating the discussion here:

@valarnin comment link

Is this necessary before we end up reworking the format and therefore the underlying classes? Seems like potential breakage mid-raid-tier that we'll end up throwing out anyways later isn't really great? I'd like to get transitioned to a new timeline format before 7.0...

@quisquous comment link

Is this necessary before we end up reworking the format and therefore the underlying classes? Uh, when and who is reworking this format? I haven't seen any momentum or discussion on this front, and personally haven't heard enough pain points to understand the motivation here.

EDIT: Sorry for the surprise on my part, but I was caught off guard with this sentiment.

The only discussion on my radar is this discord discussion: https://discord.com/channels/551474815727304704/594899820976668673/1032391897056022581. It included some discussion that locrian working on a new timeline format for lemegeton (which I asked to see, but didn't get shared; I think I saw it it once elsewhere and if that's what it is it's very XML/id heavy and hard to read; locrian would probably say "you're not supposed to read the raw format" but I think we continue to differ on the value of that). I didn't come away from that discussion thinking that "somebody will make a new timeline format and convert all timelines and tooling before 7.0".

In that same discord conversation you say "The timeline as it exists now is very, very fixed and inflexible. It would probably benefit from a significant rewrite", but it's not clear to me what your pain points are such that there would be benefits from a rewrite. (My complaints about the timeline code are largely about the the timeline controller and not the timeline format or parser.) What's on your mind, specifically?

Here are various issues I know about with timelines (in order of my own priority?):

  • making loops is tedious, and tedious to review (this issue)
  • jumps to numbers is fragile (we could probably add named labels)
  • rather than commenting out syncs, it'd be nice to add testsync that test_timeline verifies syncs at the right time but doesn't sync or adjust the time at runtime
  • (inserting some space here between the above things that I think are higher priority and the below things which I think are even lower priority / could sit forever on the backburner)
  • vague desire about labelling raidwides / tankbusters / magical vs physical vs not damage in Proposal: Adding Ways to Differentiate Timeline Mechanics #516 (I don't think we'd add this per line, because that'd get redundant, but could probably add some separate section mapping text => tags)
  • there's no state other than "what is the current time" and so there's no way to say "Ah it was A/B earlier so now this later one has to be B" without a split (however,I feel like triggers largely cover this, and even if this is a "nice to have" it's also a lot of complication and doesn't merit an entirely new timeline format, to me at least)
  • maybe it'd be nice to have some overview "what phase am I in" header line like we discussed in discord (I think this is easily solvable within the bounds of the existing timeline structure)
  • some timelines are hard to start correctly (e.g. castrum in bozja, because you can see multiple timelines at once, but this also barely comes up)
  • no way to handle parallel timelines (e.g. a8s robot phase with different phasing on different robots; arguably this just isn't an issue in nearly any encounters, and so I wouldn't design anything around this problem until is showed up again)

Things I don't think we should change:

  • calling things "raidwide" vs "Gluttony's Augur" (I think there's too many aoes and tankbusters that are different to just call them that; having real names helps [me] associate the in game ability with the action, it makes translations automatic, and I think some sort of icon/color tagging is a better solution here)

I feel a little bit "bought in" to the current timeline format. We've got make_timeline tools for both network log files and fflogs. We've got test_timeline. We've got syntax highlighting. We've got ~240 existing timelines. Mostly my feeling is that if there's truly a need for a new timeline format, I'd like to understand what the needs are, why the current timeline format can't satisfy it, and what the plan is for converting the old timelines and the tooling to the new format.

As for forcejump, my feeling is that any hypothetical new timeline format will need some (automatic) conversion from the old format, and will almost certainly support loops and this sort of thing, and so hypothetically I'll just assume that we could add some conversion for forcejump as well. If anything, it adds more information to the timeline than what is already there.

@valarnin comment link

I think my biggest issues with the current format (aside from what you already mentioned) can be summarized as:

  1. There's no way to handle logic as part of the timeline. Something like GolbezEx would benefit greatly from some sort of logic control due to the way the stored mechanics work, similarly with e12s's stored mechanics
  2. There's no way for a trigger to interact with the timeline (be that a normal triggers trigger, or a timelineTriggers trigger).

    • By interact, I mean something like:
    • check some conditions, and jump to this time
    • alter the text of this timeline entry based on some condition
    • hide this timeline entry based on some condition
    • adjust the duration of this timer bar based on some condition
  3. There's no good way to reference a specific timeline entry. e.g. let's say I want to change the p9s 272.2 "Gluttony's Augur" entry to be something like 272.2 "Gluttony's Augur (heal check)", there's no way to target that specific timeline entry and override it without also clobbering any other entry with the same text of Gluttony's Augur
  4. The timeline format really doesn't handle multiple different encounters in the same zone very well. e.g:

    • the variant dungeon conversation that was part of the discord conversation you linked
    • something like Delubrum Reginae where parties are handling different sets of mechanics
    • The Copied Factory's Hobbes fight

As for discussion about a new format, I remember some other conversation in Discord where some new example formats were thrown about, something about a yml type format and something else that I can't recall off the top of my head. Discord search is just as bad as always though and I can't find them.

@xiashtra comment link

  • jumps to numbers is fragile (we could probably add named labels)

I haven't thought too much about what would be nice to have in the timeline format, but being able to jump to a label instead of a time would definitely be on the list. It's very easy to modify a timeline and forget to adjust the jumps currently.

It also feels kind of hacky right now the way encounters in the same zone have to be separated by arbitrarily increasing the times of the subsequent encounters. If there was a way to say, label an encounter block and then jump to that block at the appropriate time, instead of increasing the later encounters by +1000, +2000, etc., like we currently do. Bozjan Southern Front and Zadnor are good examples of where it would be really useful.

quisquous commented 1 year ago

I agree that a lot of things you list and I've listed are nice, but I also still don't feel like any of them are "this is a major unsolved problem that merits rewriting the world" either. Many of them still feel like they can be solved within the bounds of the existing format.

Here's what I'm looking for:

I think I'm just trying to think practically about this. I (personally) don't feel invested in a rewrite everything project, and so if somebody wants to do it, I'd need them to drive the vast bulk of the work. Sorry if I am coming off as negative here, it's more just that I am always a practical engineer at heart (so I need to understand the motivation for larger rewrites) and also that I see my own time and energy limits (and don't want to be left holding somebody else's half-finished feature, I say as I just PR'd finishing up netparams for regexes <_<).

I think my biggest issues with the current format (aside from what you already mentioned) can be summarized as:

  1. There's no way to handle logic as part of the timeline. Something like GolbezEx would benefit greatly from some sort of logic control due to the way the stored mechanics work, similarly with e12s's stored mechanics

Yeah, this is what I meant by there's no state other than "what is the current time", like you're in a choose your own adventure book. I don't have a good picture of what this would look like in the current format or even in a new format. It seems hard to do in the existing format, for sure. There's also stuff like xp's work that reads the timeline format in Java, so inserting something like TypeScript/JavaScript into the timeline itself starts being iffy if we don't want to cause them extra work.

  1. There's no way for a trigger to interact with the timeline (be that a normal triggers trigger, or a timelineTriggers trigger).

    • By interact, I mean something like:
    • check some conditions, and jump to this time
    • alter the text of this timeline entry based on some condition
    • hide this timeline entry based on some condition
    • adjust the duration of this timer bar based on some condition

The one use case of this that I have encountered so far is that I half-solved the Castrum Lacus Litore first boss "are you up or down" by injecting a "is your player name hit by an aoe" into the timeline. This sometimes doens't work (because there's too many people and you get missed). But, that's the only time this has come up for me.

I think "alter the text of this timeline entry" is largely "hey we found out this was a stack earlier, and now this later thing is a spread". It's a minor nicety, but I feel like triggers largely handle this, and so it's largely fine for me if the timeline is still general.

It's not impossible, but I think we could add timeline controller hooks hanging off of data to jump / change text / etc from triggers. In some ways it seems like the same correspondence problem as "how to reference a specific timeline entry".

  1. There's no good way to reference a specific timeline entry. e.g. let's say I want to change the p9s 272.2 "Gluttony's Augur" entry to be something like 272.2 "Gluttony's Augur (heal check)", there's no way to target that specific timeline entry and override it without also clobbering any other entry with the same text of Gluttony's Augur

I think this is less about the timeline format and more about overrides (and convenience/implementation of doing them).

You could (technically but awkwardly) do this now with existing tools by hiding the other Gluttony's Augur entries and adding custom entries with the text you wanted. Another technically existing solution is that you (as a cactbot developer) could send a PR to number anything you think needs to be handled differently (like I numbered Ultimas in P12S2 so I personally could remember which ones I was mitting) and then the different text would let you do this.

In terms of how to add this to the UI for everybody, I think it then gets into a correspondence problem of how to refer to this particular Gluttony's Augur (and have it continue to correspond across future changes). I deliberately sidestepped this problem by making people override the the text globally instead. Here's some ideas, though:

In either case, somebody would need to add some config UI for this. But, I think either of these is plausible within the existing timeline format.

From the brief glance at whatever xml (Lemegeton?) timeline format went by (and also a long time ago cactbot request from xp that I said no to), it looks like they are solving this by adding ids to every single timeline entry. (I wonder if maybe this is what you're getting at in terms of why "ways to specify a timeline entry" is part of a discussion of timeline format.) I (personally) find this unpleasant, hard to write, hard to read, hard to review. One thing I really like about the timeline format is that it's easy to digest visually as a programmer and I don't need extra tools, and extra stuff like an id on every single line is not a desired solution for me. I also don't know that this necessarily solves the correspondence problem either, as if somebody adds a fork to a timeline or collapses a loop or something then what happens to those ids?

  1. The timeline format really doesn't handle multiple different encounters in the same zone very well. e.g:

    • the variant dungeon conversation that was part of the discord conversation you linked
    • something like Delubrum Reginae where parties are handling different sets of mechanics
    • The Copied Factory's Hobbes fight

I don't know that any of these examples really feel that compelling to me. For Hobbes, I don't know that you need to see what the other parties are doing as you don't interact at all. Similarly, DRS has one person doing a solo fight while the other folks fight the second boss and it doesn't need to be simultaneous. Variant dungeon also ended up fine in the end and didn't need this sort of thing. The only fight that even remotely feels like multiple timelines would be helpful to me would be a8s where there's multiple robots with different push times.

I think to me this feels currently like an edge case and not something to build an entire format around. Even if we did have multiple timelines, I'd also want to think about the UI to present them, as maybe we'd want a second timeline next to the first instead of squishing them together?

As for discussion about a new format, I remember some other conversation in Discord where some new example formats were thrown about, something about a yml type format and something else that I can't recall off the top of my head. Discord search is just as bad as always though and I can't find them.

Yeah, I can't find it either.

quisquous commented 1 year ago

@xiashtra comment link

  • jumps to numbers is fragile (we could probably add named labels)

I haven't thought too much about what would be nice to have in the timeline format, but being able to jump to a label instead of a time would definitely be on the list. It's very easy to modify a timeline and forget to adjust the jumps currently. It also feels kind of hacky right now the way encounters in the same zone have to be separated by arbitrarily increasing the times of the subsequent encounters. If there was a way to say, label an encounter block and then jump to that block at the appropriate time, instead of increasing the later encounters by +1000, +2000, etc., like we currently do. Bozjan Southern Front and Zadnor are good examples of where it would be really useful.

5760 adds named labels as a draft. I think a reasonable followup here is what @xiashtra is suggesting to add "named blocks". In my mind, a named block is some number of lines in a timeline grouped together. However, its times are in a parallel universe from the normal timeline. It can't be jumped into or out of other than via jump to label. This would allow for having a bunch of encounters in a dungeon that all start at "0". This would also reduce the number of global active syncs (since you'd have a couple of syncs at the beginning rather than syncs that cover all fights). This could theoretically be used in some very hypothetical system to play multiple timelines at once.

Here's an example, BLOCKSTART and BLOCKEND is not how I would suggest to write this but just as a hypothetical for discussion:

# Lapis Manalis

0.0 "--sync--" sync / 00:0839::The Silvan Throne will be sealed off/ window 0,1 jump "albion"
0.0 "--sync--" sync / 00:0839::The Forum Messorum will be sealed off/ window 0,1 jump "galatea"
0.0 "--sync--" sync / 00:0839::Deepspine will be sealed off/ window 0,1 jump "cagnazzo"

BLOCKSTART
0.0 label "albion"
0.0 "--sync--" sync / 00:0839::The Silvan Throne will be sealed off/ window 0,1
6.0 "--sync--" sync / 1[56]:[^:]*:Albion:802C:/
10.6 "Call of the Mountain" sync / 1[56]:[^:]*:Albion:7A7C:/
# etc
BLOCKEND

BLOCKSTART
0.0 label "galatea"
0.0 "--sync--" sync / 00:0839::The Forum Messorum will be sealed off/ window 0,1
10.2 "--sync--" sync / 1[56]:[^:]*:Galatea Magna:7F71:/ # manually added for early sync
15.2 "Waxing Cycle/Waning Cycle" sync / 1[56]:[^:]*:Galatea Magna:(7A91|7F6E):/
#etc
BLOCKEND

BLOCKSTART
0.0 label "cagnazzo"
0.0 "--sync--" sync / 00:0839::Deepspine will be sealed off/ window 0,1
15.6 "Stygian Deluge" sync / 1[56]:[^:]*:Cagnazzo:79A3:/
25.4 "--sync--" sync / 1[56]:[^:]*:Cagnazzo:798F:/
38.0 "Antediluvian 1" sync / 1[56]:[^:]*:Cagnazzo:7990:/
#etc
BLOCKEND
xiashtra commented 1 year ago

5760 adds named labels as a draft. I think a reasonable followup here is what @xiashtra is suggesting to add "named blocks". In my mind, a named block is some number of lines in a timeline grouped together. However, its times are in a parallel universe from the normal timeline. It can't be jumped into or out of other than via jump to label. This would allow for having a bunch of encounters in a dungeon that all start at "0". This would also reduce the number of global active syncs (since you'd have a couple of syncs at the beginning rather than syncs that cover all fights). This could theoretically be used in some very hypothetical system to play multiple timelines at once.

Here's an example, BLOCKSTART and BLOCKEND is not how I would suggest to write this but just as a hypothetical for discussion:

This is pretty much exactly what I was thinking of.

xpdota commented 1 year ago

Blocks are nice. I think they could be enhanced further by giving the block itself a name, rather than just relying on labels within the block. You could then have a "blockname:labelname" syntax for jumps, so that simple label names can still be re-used for multiple fights (like "start"). If a jump is unqualified, a matching label within the same block would take precedence, i.e. "start" would jump to the start of the current block, while "phase2:start" would jump to "start" in "phase2". Maybe have a "blockname:" syntax to just go to the start of a block.

Regarding state, loops, branching, etc:

I see the value in having a fancier syntax, especially with regards to branching mechanics and loops. For that, a "composition" approach might be nice. For something like P8S1, rather than the current approach of having two timelines copy-pasted with times changed, you could just make each mechanic its own named block, and then instead of two gigantic timelines, you just have 8 or so lines for each one, and you don't have to worry about editing both if you want to add or correct something.

A way to handle some of the delayed mechanics could be a "mixin" approach, where you tell it to add a named block to the current timeline entries, rather than jumping to it.

However,

now that we've established that there's plenty of technical ways that timelines could be better, there's the question of how fancy they should get. One of the popular uses of timeline editing is to throw your mitigations and such onto the timeline. You might need to have a different mit plan for different branches (e.g. P8S dog first vs snake first), or use different mits on different iterations of a looping mechanic. Then, as mentioned in other comments, you have to have some way of visualizing all of that in an editor.

If new functionality can be unrolled entirely with pre-processing, then it shouldn't affect users much, since you could just pre-unroll the whole thing and let them edit as it was previously, while still reducing the effort.

There's also stuff like xp's work that reads the timeline format in Java, so inserting something like TypeScript/JavaScript into the timeline itself starts being iffy if we don't want to cause them extra work.

There are some ways to handle this which range from decent to downright cursed (JCEF, J2V8, only allow JS syntax that is also valid Groovy, etc) but I'd be more worried about the fact that this sounds like it would involve eval() in some form. Also it would make the timeline parsing itself more complex if you wanted to support multiline expressions.