Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview mode for quickfort #2018

Closed
myk002 opened this issue Feb 27, 2022 · 5 comments · Fixed by DFHack/scripts#392
Closed

Preview mode for quickfort #2018

myk002 opened this issue Feb 27, 2022 · 5 comments · Fixed by DFHack/scripts#392
Assignees
Labels
idea Suggestions, etc.
Projects

Comments

@myk002
Copy link
Member

myk002 commented Feb 27, 2022

The more I thought about this feature, the more I realized that it needs a design doc, or at least somewhere to gather my thoughts. So here it is.

The vision:
After a blueprint is selected in the quickfort ui (or if --preview is passed on the commandline), a sidebar overlay viewscreen is shown and the cursor becomes active. Flashing X's appear where the blueprint will make changes to the map. The user can move the cursor (and use other hotkeys to apply euclidean transformations) and the blueprint shadow will change accordingly. The user can also "lock" the blueprint so the cursor can be used to shift the viewport and examine parts of the blueprint shadow that were originally offscreen (or on different z-levels). Enter applies the blueprint to the map, Esc cancels.

A technical challenge we need to address is that the ui needs to remain responsive to cursor movement, but the calculations for generating the blueprint "shadow" can be slow. This implies usage of lua coroutines and requires a design for explicit yielding to the graphical rendering stack.

Well, actually, let me think about the assumption that shadow calculation will be slow. My concern comes from observing the execution of large query blueprints, which can take multiple seconds. However, query blueprints won't be executed when generating previews. Just the tile locations where the query commands will be run are required. Perhaps I should approach this more iteratively.

First, I'll implement the preview UI and logic without coroutines and measure the responsiveness. What's the threshold? It should be low enough that the user doesn't feel that the cursor is frustratingly "laggy". Let's say 5ms max latency for calculating and rendering a shadow across all of Dreamfort's blueprints. Dreamfort has a good mix of simple and complicated blueprints that should provide good coverage of likely use cases.

Some thoughts on how to generate the previews:

If a preview is required, set preview={unclipped={}, clipped={}, bounds={}, invalid_tiles=0} in the ctx. As we run through the blueprint(s), set preview.unclipped[z][y][x] to true if something is on the blueprint at that tile position, and set the clipped coordinate to true or false according to whether the map would actually be changed at that position (i.e. it's a valid tile for the proposed change). When assigning false, increment the invalid_tiles counter. Only record clipped for the first blueprint that covers that tile. We don't want to mark a tile as bad if a later blueprint in a meta blueprint depends on an earlier one (e.g. meta plays a place then a query. The query blueprint depends on the stockpiles being there). Track min and max x, y, and z in the bounds table so we know what ranges to scan while rendering.

Note: this could potentially subsume the implementation of --pretend. Is there ever a case where we want the preview but pretend is false?

When rendering the overlay in the viewscreen, clip the preview bitmap to the viewport and render green Xs for coordinates that are true in clipped and red Xs for coordinates that are false in clipped but true in unclipped.

If I end up having to make the preview generation process interruptable, here are some thoughts about how I'd do it:

Use script.start() to process the blueprints when generating previews. Add to ctx a cancel flag and a function that will:

  • check to see if 5ms (or whatever threshold we decide on) has elapsed since the last check
  • if it has, then call script.sleep(1, 'frames') to yield control to the UI
  • render whatever is in the preview table so far
  • if the cursor has moved, set the cancel flag and start a new preview in a new context

In the blueprint processors, we'll call the function and abort processing if the cancel flag is set. We'll have to add calls and checks in any loop that can take more than 5ms to execute.

If we do implement interruptibility, it will also enable quickfort to show progress when running blueprints instead of just showing a black screen until the blueprint is completely applied.

UI design:

Blueprint "shadow" appears on the map on the tiles where modifications would occur if the blueprint were applied at the current cursor location. Tiles where the blueprint would successfully be applied flash with green X characters. Tiles where the blueprint would attempt to make a change but fail (invalid tile, out of bounds, etc.) flash with red X characters.

Total invalid tile count (including tiles offscreen) is displayed in the menu overlay area.

Movement keys: move cursor and viewport. If blueprint is not locked, also move blueprint start location

l: lock blueprint start location, allowing user to see blueprint preview outside of the original viewport and other z-levels. If blueprint is locked, this unlocks the blueprint and jumps the cursor to the tile that it was on when the blueprint was locked.

L: (only appears when locked) unlock and jump the blueprint start position to the current cursor position

r: repeat. cycles through "None", "Up", and "Down"
R: (only appears when repeat is not "None". edit box for inputting how many times to repeat

Ctrl Up: apply vflip transformation
Ctrl Down: apply hflip transformation
Ctrl Left: apply rotccw transformation
Ctrl Right: apply rotcw transformation
x: clear all transformations
X: remove last transformation

As transformations are applied, they are listed on the menu overlay panel.

Enter applies the blueprint, Escape exits the viewscreen without applying

@myk002 myk002 self-assigned this Feb 27, 2022
@myk002 myk002 added the idea Suggestions, etc. label Mar 5, 2022
@myk002
Copy link
Member Author

myk002 commented Apr 4, 2022

After tinkering with the preview screen for a bit, I've come to a realization: this screen should not be an interstitial. it should be the main quickfort UI.

we don't need a --preview flag. just sending the regular quickfort commandline to quickfort gui (or gui/quickfort) should load up all the params, pre set the gui state, and start the preview.

e.g. what I envisioned as quickfort run someblueprint.csv --preview now becomes quickfort gui someblueprint.csv (or gui/quickfort someblueprint.csv).

if a blueprint is already specified on the commandline, a preview for that blueprint is loaded. otherwise the blueprint list dialog (the current "UI") is shown. we can move command selection to the "preview" ui. Oh, this opens up a world of possibilities!

@myk002
Copy link
Member Author

myk002 commented Apr 4, 2022

add notice to sidebar describing what the blueprints do (e.g. "This blueprint will designate buildings and send keystrokes to the DF UI to configure individual tiles" or "this blueprint will send keystrokes to the DF UI to change options, but will not affect any tiles directly")

add messagebox showing which orders will be enqueued if the user hits the "Generate manager orders" hotkey

add "Undo" hotkey

@myk002
Copy link
Member Author

myk002 commented Apr 29, 2022

TODO: don't display an invalid tile when the blueprint designates a tile for tree chopping and there is no tree there

@myk002
Copy link
Member Author

myk002 commented Apr 30, 2022

TODO: show how many orders will be enqueued next to the 'o' hotkey label. Don't show popup if no orders were enqueued (though still show the empty pop-up if the orders preview was selected with 'O').

@myk002
Copy link
Member Author

myk002 commented Apr 30, 2022

Change 'o' to a toggle that automatically enqueues orders on run. Add an "enqueue now" hotkey to the orders preview pop-up

@myk002 myk002 added this to To do in 0.47.05-r6 via automation May 9, 2022
@myk002 myk002 moved this from To do to In progress in 0.47.05-r6 May 9, 2022
@myk002 myk002 moved this from In progress to Bug shortlist in 0.47.05-r6 May 29, 2022
@myk002 myk002 moved this from Bug shortlist to To do in 0.47.05-r6 May 31, 2022
0.47.05-r6 automation moved this from To do to Done Jun 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
idea Suggestions, etc.
Projects
No open projects
Development

Successfully merging a pull request may close this issue.

1 participant