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

update timestream #1206

Merged
merged 10 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Template for new versions:
- `fix/population-cap`: fixes the situation where you continue to get migrant waves even when you are above your configured population cap
- `fix/occupancy`: fixes issues where you can't build somewhere because the game tells you an item/unit/building is in the way but there's nothing there
- `fix/sleepers`: (reinstated) fixes sleeping units belonging to a camp that never wake up.
- `timestream`: (reinstated) keep the game running quickly even when there are large numbers of units on the map

## New Features
- `buildingplan`: dimension tooltip is now displayed for constructions and buildings that are designated over an area, like bridges and farm plots
Expand Down
155 changes: 119 additions & 36 deletions docs/timestream.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,135 @@ timestream

.. dfhack-tool::
:summary: Fix FPS death.
:tags: unavailable
:tags: fort gameplay fps

Do you remember when you first start a new fort, your initial 7 dwarves zip
around the screen and get things done so quickly? As a player, you never had
to wait for your initial dwarves to move across the map. Don't you wish that
your fort of 200 dwarves could be as zippy? This tool can help.
to wait for your initial dwarves to move across the map. Do you wish that your
fort of 200 dwarves and 800 animals could be as zippy? This tool can help.

``timestream`` keeps the game running quickly by dynamically adjusting the
calendar speed relative to the frames per second that your computer can support.
Your dwarves spend the same amount of in-game time to do their tasks, but the
time that you, the player, have to wait for the dwarves to do things speeds up.
This means that the dwarves in your fully developed fort appears as energetic as
a newly created one, and mature forts are much more fun to play.
``timestream`` keeps the game running quickly by tweaking the game simulation
according to the frames per second that your computer can support. This means
that your dwarves spend the same amount of time relative to the in-game
calendar to do their tasks, but the time that you, the player, have to wait for
the dwarves to do get things done is reduced. The result is that the dwarves in
your fully developed fort appear as energetic as the dwarves in a newly created
fort, and mature forts are much more fun to play.

If you just want to change the game calendar speed without adjusting dwarf
speed, this tool can do that too. Your dwarves will just be able to get
less/more done per season (depending on whether you speed up or slow down the
calendar).
Note that whereas your dwarves zip around like you're running at 100 FPS, the
onscreen FPS counter, if enabled, will still show a lower number. See the
`Technical details`_ section below if you're interested in what's going on
under the hood.

You can also use this tool to change the in-game calendar speed. Your dwarves
will be able to get less/more done per season (depending on whether you speed
up or slow down the calendar).

Usage
-----

``timestream --units [--fps <target FPS>]``
Keep the game running as responsively as it did when it was running at the
given frames per second. Dwarves get the same amount done per game day, but
game days go by faster. If a target FPS is not given, it defaults to 100.
``timestream --rate <rate>``, ``timestream --fps <target FPS>``
Just change the rate of the calendar, without corresponding adjustments to
units. Game responsiveness will not change, but dwarves will be able to get
more (or less) done per game day. A rate of ``1`` is "normal" calendar
speed. Alternately, you can run the calendar at a rate that it would have
moved at while the game was running at the specified frames per second.
::

enable timestream
timestream [status]
timestream set <key> <value>
timestream reset

Examples
--------

``timestream --units``
Keep the game running as quickly and smoothly as it did when it ran
"naturally" at 100 FPS. This mode makes things much more pleasant for the
player without giving any advantage/disadvantage to your in-game dwarves.
``timestream --rate 2``
Calendar runs at 2x normal speed and units get half as much done as usual
per game day.
``timestream --fps 100``
Calendar runs at a dynamic speed to simulate 100 FPS. Units get a varying
amount of work done per game day, but will get less and less done as your
fort grows and your unadjusted FPS decreases.
``timestream --rate 1``
Reset everything back to normal.
``enable timestream``
Start adjusting the simulation to run at the currently configured apparent
FPS (default is whatever you have the FPS cap set to in the DF settings,
which is usually 100).

``timestream set fps 50``
Tweak the simulation so dwarves move at an apparent 50 frames per second.

``timestream set calendar-rate 0.5``
Make the days twice as long and allow dwarves to accomplish twice as much
per day (as long as the target FPS is sufficiently above the FPS the game
is actually running at).

``timestream reset``
Reset settings to defaults: the vanilla FPS cap with no calendar speed
advantage or disadvantage.

Settings
--------

:fps: Set the target simulated FPS. The default target FPS is whatever you have
the FPS cap set to in the DF settings, and the minimum is 10. Setting the
target FPS *below* your current actual FPS will have no effect. You have
to set the vanilla FPS cap for that. Set a target FPS of -1 to make no
adjustment at all to the apparent FPS of the game.

:calendar-rate: Set the calendar rate in relation to the target FPS. A calendar
rate factor of 1 means time flows "normally" for the units in the game.
Values between 0 and 1 slow the calendar relative to the world, allowing
units to get more done per day, and values above 1 speed the calendar
relative to the world, causing the days to pass quicker and preventing
units from getting as much done per day. The actual fps must be below the
configured target ``fps`` setting for the ``calendar-rate`` setting to take
effect.

:max-frame-skip: Set the maximum number of ticks that can be skipped in one
step. Dwarves can perform at most one action per step, and if too many
frames are skipped in one step, dwarves will "lose time" compared to the
movement of the calendar. The default is 4, which allows a target FPS of up
to 4x your actual FPS while still allowing dwarves to walk at full speed.
Raise this value if speed of the simulation is more important to you than
its accuracy and smoothness.

Technical details
-----------------

So what is this magic? How does this tool make it look like the game is
suddenly running so much faster?

Maybe an analogy would help. Pretend you're standing at the bottom of a
staircase and you want to walk up the stairs. You can walk up one stair every
second, and there are 100 stairs, so it will take you 100 seconds to walk up
all the stairs.

Now let's use the Hand of Armok and fiddle with reality a bit. Let's say that
instead of walking up one step, you walk up 5 steps at once. At the same time
we move the wall clock 5 seconds ahead. If you look at the clock after reaching
the top of the stairs, it will still look like it took 100 seconds, but you did
it all in fewer "steps".

That's essentially what ``timestream`` is doing to the game. All "actions" in
DF have counters associated with them. For example, when a dwarf wants to walk
to the next tile, a counter is initialized to 500. Every "tick" of the game
(the "frame" in FPS) decrements that counter by by a certain amount. When the
counter gets to zero, the dwarf appears on the next tile.

When ``timestream`` is active, it monitors all those counters and makes them
decrement more per tick. It then balances things out by proportionally
advancing the in-game calendar. Therefore, more "happens" per step, and DF has
to simulate fewer "steps" for the same amount of work to get done.

The cost of this simplification is that the world becomes less "smooth". As the
discrepancy between the "natural" and simulated FPS grows, more and more
dwarves will move to their next tiles at *exactly* the same time. Moreover, the
rate of action completion per unit is effectively capped at the granularity of
the simulation, so very fast units will lose some of their advantage. In the
extreme case, with the computer struggling to run at 1 FPS and ``timestream``
simulating thousands of FPS (and the ``max-frame-skip`` cap increased to 20),
all units will perform exactly one action per frame. This would make the game
look robotic. With default settings, it will never get this bad, but you can
always choose to alter the ``timestream`` configuration to your preferred
balance of speed vs. accuracy.

Limitations
-----------

Right now, not all aspects of the game are perfectly adjusted. For example,
armies on world map will move at the same (real-time) rate regardless of
changes that ``timestream`` is making to the calendar.

Here is a (likely incomplete) list of game elements that are not affected by
``timestream``:

- Army movement across the world map (including raids sent out from the fort)
- Liquid movement and evaporation
1 change: 1 addition & 0 deletions internal/control-panel/registry.lua
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ COMMANDS_BY_IDX = {
desc='Displays percentages on partially-consumed items like hospital cloth.'},
{command='pop-control', group='gameplay', mode='enable'},
{command='starvingdead', group='gameplay', mode='enable'},
{command='timestream', group='gameplay', mode='enable'},
{command='work-now', group='gameplay', mode='enable'},
}

Expand Down
Loading