<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/libTAS/feed.xml" rel="self" type="application/atom+xml" /><link href="/libTAS/" rel="alternate" type="text/html" /><updated>2026-03-13T17:53:27+00:00</updated><id>/libTAS/feed.xml</id><title type="html">libTAS</title><subtitle>libTAS is a software for Linux that provides TAS tools to games, such as frame advance, inputs recording, savestates.</subtitle><author><name>Clément Gallet</name></author><entry><title type="html">What’s new in v1.4.7</title><link href="/libTAS/2025/10/06/version-147.html" rel="alternate" type="text/html" title="What’s new in v1.4.7" /><published>2025-10-06T00:00:00+00:00</published><updated>2025-10-06T00:00:00+00:00</updated><id>/libTAS/2025/10/06/version-147</id><content type="html" xml:base="/libTAS/2025/10/06/version-147.html"><![CDATA[<p>Here is a summary of the main changes in v1.4.7. You can see the full changelog
file <a href="https://github.com/clementgallet/libTAS/blob/v1.4.7/CHANGELOG.md">here</a>.</p>

<h3 id="input-editor">Input editor</h3>

<h4 id="undo">Undo</h4>

<p>Most input editor operations are now stored, and can be undone. This can be
performed using contextual menu, shortcuts, or using the undo window which 
shows past actions and those which can be undone. Indeed, undo operations cannot
modify inputs before the current frame.</p>

<p>The only operations that are not registered are when loading a savestate with
its inputs. In that case, the undo history is reset.</p>

<h4 id="factor-analog-inputs">Factor analog inputs</h4>

<p>This feature has been asked a lot. It is now possible to multiply the values of
a single analog input (like mouse coordinates) by a factor. This will help porting
inputs when the game window resolution has changed.</p>

<h4 id="add-input-columns">Add input columns</h4>

<p>There is now a unified way to add input columns, especially analog inputs, using
the “inputs” menu. You don’t to set a new value to an analog input to add it to
the editor. As a consequence, using the mouse wheel to change its value has been
removed.</p>

<h3 id="ram-watch">Ram watch</h3>

<p>It has a few new features:</p>
<ul>
  <li>ram watches can be frozen</li>
  <li>new types: string and byte array</li>
  <li>ram watches can be reordered</li>
</ul>

<h3 id="hex-viewer">Hex viewer</h3>

<p>A minimal hex viewer has been added, so that you can visualize the game memory.
You can seek an address from the ram watch or ram search tools. Selecting bytes
in the hex viewer will display the converted integer or float values. Also, 
modified bytes are highlighted.</p>

<h3 id="savestates">Savestates</h3>

<p>As a critical part of the tool, savestating feature has received some improvements:</p>

<h4 id="savefiles">Savefiles</h4>

<p>Files that are created or modified by the game (aka savefiles) were incorrectly
left out of savestates. This is now fixed, but will cause an increase in 
savestate size. To mitigate this, a few tricks have been developed:</p>

<p>We map the savefile in memory. If the original file is present, we map it also.
We compare the both memory regions, and we only store the memory pages that are
different. When loading the savestate, we also map both files to memory, and we
copy either from the original file or from the savestate into the savefile.</p>

<p>If the original file does not exist, we save the whole file into the savestate.</p>

<p>Mapped files can have holes in them. We can detect them using <code class="language-plaintext highlighter-rouge">lseek()</code> with 
<code class="language-plaintext highlighter-rouge">SEEK_DATA</code> and <code class="language-plaintext highlighter-rouge">SEEK_HOLE</code> arguments, and skip pages which are inside a hole.
Calling <code class="language-plaintext highlighter-rouge">lseek()</code> requires that we have a file descriptor associated with the
mapped file. In the special case of shared files that were mapped and then
closed, we can still have access to a file descriptor inside <code class="language-plaintext highlighter-rouge">/proc/self/map_files/</code>.
Getting access to this directory requires <code class="language-plaintext highlighter-rouge">CAP_CHECKPOINT_RESTORE</code> since
Linux 5.9. Before that, it requires <code class="language-plaintext highlighter-rouge">CAP_SYS_ADMIN</code>. libTAS program now asks at
startup to add <code class="language-plaintext highlighter-rouge">CAP_CHECKPOINT_RESTORE</code> to the executable.</p>

<p>In the case that the game manipulates a file using only the file stream given
by <code class="language-plaintext highlighter-rouge">fopen()</code>, without ever needing the underlying file descriptor, we have a
strong optimization! Instead of opening the file, we map the file in memory 
with private mapping, and we create a stream that gives access to the memory 
mapping directly (using <code class="language-plaintext highlighter-rouge">fopencookie()</code>). The advantages are:</p>

<ul>
  <li>Because the mapping is private, the original file is never modified</li>
  <li>The file content is automatically included in savestates</li>
  <li>We benefit from the copy-on-write mechanism: no memory is allocated until the
file mapping is modified. We can detect if a memory page from the mapping has
been modified using the <code class="language-plaintext highlighter-rouge">file-page</code> flag from <code class="language-plaintext highlighter-rouge">/proc/pid/pagemap</code> file. This
way, we are sure to only save memory pages that have been modified from the 
original file.</li>
</ul>

<p>This feature is crucial for programs like <code class="language-plaintext highlighter-rouge">pcem</code>, which modifies the image disk
of the virtual machine, possibly taking several gigabytes of memory.</p>

<h4 id="pid-manipulation">PID manipulation</h4>

<p>When a savestate needs to be recreated, we are attempting to give it the same
pid it has before. This is possible using two recent features:</p>

<ul>
  <li>the “/proc/sys/kernel/ns_last_pid” file which can be modified to manipulate the
next pid value</li>
  <li>the more recent <code class="language-plaintext highlighter-rouge">clone3</code> syscall which has a <code class="language-plaintext highlighter-rouge">set_tid</code> option</li>
</ul>

<p>Having the same pid everytime can mitigate some game crashes.</p>]]></content><author><name>Clément Gallet</name></author><summary type="html"><![CDATA[Here is a summary of the main changes in v1.4.7. You can see the full changelog file here.]]></summary></entry><entry><title type="html">What’s new in v1.4.6</title><link href="/libTAS/2024/06/25/version-146.html" rel="alternate" type="text/html" title="What’s new in v1.4.6" /><published>2024-06-25T00:00:00+00:00</published><updated>2024-06-25T00:00:00+00:00</updated><id>/libTAS/2024/06/25/version-146</id><content type="html" xml:base="/libTAS/2024/06/25/version-146.html"><![CDATA[<p>Here is a summary of the main changes in v1.4.6. You can see the full changelog
file <a href="https://github.com/clementgallet/libTAS/blob/v1.4.6/CHANGELOG.md">here</a>.</p>

<h3 id="imgui-interface">ImGui interface</h3>

<p>The libTAS game HUD was rewritten to use ImGui. It has some constraints to be
used, so it will only appear for games using OpenGL, Vulkan or SDL2 renderer 
(&gt; 2.0.18). For now, the previous elements were implemented (framecount, inputs, 
crosshair, lua, messages, ram watches). It is very easy to write for ImGui, so 
more will come.</p>

<p>A last feature is game window detach. When used, the game will not take the full
window, but will appear inside an ImGui window.</p>

<h3 id="savestates-and-threading">Savestates and threading</h3>

<p>A limitation from using savestates has existed for a very long time: the 
impossibility to load a savestate if threads have been created or destroyed.
It was very annoying to users, and made several games impossible to TAS. Some 
features were implemented to mitigate this issue, mainly the backtrack savestate
that is automatically saved after a thread was created or destroyed, to be able
to go back as early as possible. Still it was not good enough.</p>

<p>So I went ahead and started working on savestate code being able to create or
destroy threads. My main help was coming from 
<a href="https://github.com/dmtcp/dmtcp">DMTCP</a> which has a similar feature, although 
this program is created the process and all the threads, so the destroy part 
was not handled.</p>

<p>This feature is still largely untested, but has shown good results on games that
use threading a lot (like .NET games), with still crashes from time to time.
Thanks to this feature, backtrack savestates and savestate invalidation are not
needed anymore, so they were removed.</p>

<h4 id="terminate-threads">Terminate threads</h4>

<p>Terminating a thread must be performed when threads are being suspended, before 
the actual state loading. Two methods are used to terminate a thread: the first 
one is by calling <code class="language-plaintext highlighter-rouge">pthread_cancel()</code>, which is a relatively safe way to stop a 
thread, but it relies on the thread hitting a cancellation point. If this 
method times out, we signal the thread, and the signal handler calls 
<code class="language-plaintext highlighter-rouge">pthread_exit()</code> (highly unsafe).</p>

<h4 id="creating-threads">Creating threads</h4>

<p>Creating a thread must be performed after the loading state has been performed 
because the memory layout and content must be present when the thread is 
created (especially the thread stack). We use the low-level <code class="language-plaintext highlighter-rouge">clone()</code> function 
so that it does not mess with <code class="language-plaintext highlighter-rouge">pthread</code> library, and the thread function then 
calls <code class="language-plaintext highlighter-rouge">setcontext()</code> to resume execution to where it was saved.</p>

<h3 id="markers">Markers</h3>

<p>Input editor markers have been extended a bit with its own panel to handle 
markers. We can now edit a marker’s text and seek to its frame</p>

<h3 id="lua">Lua</h3>

<p>Add several new lua functions:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">memory.baseAddress()</code> to get the base address of a file loaded in the game 
process memory</li>
  <li><code class="language-plaintext highlighter-rouge">runtime.saveState()</code> and <code class="language-plaintext highlighter-rouge">runtime.loadState()</code> to save and load savestates</li>
  <li><code class="language-plaintext highlighter-rouge">runtime.isFastForward()</code> and <code class="language-plaintext highlighter-rouge">runtime.setFastForward()</code> to control 
fast-forward</li>
  <li><code class="language-plaintext highlighter-rouge">memory.readcstring()</code> to read a C-style string from memory into a lua string</li>
  <li><code class="language-plaintext highlighter-rouge">gui.quad()</code> to draw quads</li>
  <li><code class="language-plaintext highlighter-rouge">gui.text()</code> was extended to include horizontal/vertical alignment, font size 
and optional monospace font</li>
  <li><code class="language-plaintext highlighter-rouge">gui.window()</code> to draw an ImGui window that may be movable.</li>
</ul>

<p>Additionally, a few modifications were made on the callbacks:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">onPaint()</code> callback is not called when the screen is not rendering (due to 
either non-draw frame or skipping with fast-forward).</li>
  <li>Move around <code class="language-plaintext highlighter-rouge">onFrame()</code> callback so it is executed before <code class="language-plaintext highlighter-rouge">onPaint()</code>, which 
feels more natural.</li>
  <li><code class="language-plaintext highlighter-rouge">onInput()</code> can now modify inputs even in playback mode, and the modifications 
are stored inside the movie.</li>
</ul>

<h3 id="more-automated-detections">More automated detections</h3>

<ul>
  <li><strong>Autodetect missing libraries and download them</strong>: libTAS looks at libraries
missing to launch the game, and for some of them, it can download them from 
an Ubuntu package mirror and extract the library into a libTAS library folder.
This is especially important for old libraries that are not present in newer
Linux distributions. You are supposed to use the Steam runtime to launch the 
game, but having a way to get the libraries directly is better.</li>
  <li><strong>Autodetect Unity engine</strong>: When a Unity game is detected, libTAS automatically
adds <code class="language-plaintext highlighter-rouge">-force-gfx-direct</code> to the commandline options.</li>
  <li><strong>Autodetect Godot engine</strong>: When a Godot game is detected, libTAS automatically
adds <code class="language-plaintext highlighter-rouge">--audio-driver ALSA</code> to the commandline options.</li>
  <li><strong>Autodetect GameMaker Studio engine</strong>: When a GM:S game is detected, libTAS 
automatically sets time-tracking clock_gettime() monotonic option.</li>
  <li><strong>Autodetect newer Unity coroutines</strong>: The Unity hack used in v1.4.4 was only
working for old engines (before 2019/2020). Now the hack is also working for
newer engines, only if the file containing symbols (<code class="language-plaintext highlighter-rouge">UnityPlayer_s.debug</code>) is 
present in the game. This is to locate the function that threads use to wait
for new jobs to execute: <code class="language-plaintext highlighter-rouge">UnityClassic::Baselib_SystemFutex_Wait()</code>. In the 
new engines, locating loading threads is even easier because the engine does
assign a name to each thread. So we just have to look for <code class="language-plaintext highlighter-rouge">Loading.Preload</code>, 
<code class="language-plaintext highlighter-rouge">Loading.AsyncRe</code>, <code class="language-plaintext highlighter-rouge">Background Job.</code> and <code class="language-plaintext highlighter-rouge">Job.Worker [N]</code>.</li>
</ul>]]></content><author><name>Clément Gallet</name></author><summary type="html"><![CDATA[Here is a summary of the main changes in v1.4.6. You can see the full changelog file here.]]></summary></entry><entry><title type="html">What’s new in v1.4.5</title><link href="/libTAS/2023/11/18/version-145.html" rel="alternate" type="text/html" title="What’s new in v1.4.5" /><published>2023-11-18T00:00:00+00:00</published><updated>2023-11-18T00:00:00+00:00</updated><id>/libTAS/2023/11/18/version-145</id><content type="html" xml:base="/libTAS/2023/11/18/version-145.html"><![CDATA[<p>Here is a summary of the main changes in v1.4.5. You can see the full changelog
file <a href="https://github.com/clementgallet/libTAS/blob/v1.4.5/CHANGELOG.md">here</a>.</p>

<h3 id="new-lua-interface">New lua interface</h3>

<p>Lua scripting has been rewritten with a dedicated window for showing running
scripts. Individual scripts can be enabled/disabled, and each script has its
own context, so that functions/globals do not collide. A new callback system is
present to allow multiple functions to be added to a single callback. Old
scripts are still supported as being translated into the new system. Moreover,
when users modify a running script, it is automatically refreshed.</p>

<h3 id="revamp-settings">Revamp settings</h3>

<p>libTAS menus grow more and more, and it was getting difficult for users to 
navigate them. Most of the settings are now moved their own window with different
tabs, while tools and common settings that you may change during the run are
kept in the main menu.</p>]]></content><author><name>Clément Gallet</name></author><summary type="html"><![CDATA[Here is a summary of the main changes in v1.4.5. You can see the full changelog file here.]]></summary></entry><entry><title type="html">What’s new in v1.4.3</title><link href="/libTAS/2022/04/10/version-143.html" rel="alternate" type="text/html" title="What’s new in v1.4.3" /><published>2022-04-10T00:00:00+00:00</published><updated>2022-04-10T00:00:00+00:00</updated><id>/libTAS/2022/04/10/version-143</id><content type="html" xml:base="/libTAS/2022/04/10/version-143.html"><![CDATA[<p>Here is a summary of the main changes in v1.4.3. You can see the full changelog
file <a href="https://github.com/clementgallet/libTAS/blob/v1.4.3/CHANGELOG.md">here</a>.</p>

<h3 id="new-ram-search">New RAM Search</h3>

<p>The RAM search feature has been completely rewritten. Previously it was storing
all results in memory, and too many results would crash the program. The new
implementation is based on what Cheat Engine is doing:</p>

<ul>
  <li>Store all results on disk, and split memory addresses and memory values into
separate files.</li>
  <li>Split the process into multiple threads, each thread writing into its own
files. At the end, all files are merged together.</li>
  <li>If we need to read at least two addresses from the same memory page, read the
entire page to benefit from caching</li>
  <li>Don’t display results if the result count is above a certain threshold</li>
</ul>

<h3 id="improved-input-editor-rewind-feature">Improved input editor rewind feature</h3>

<p>The ability to change past inputs in the input editor, with an automated state
loading and fast-forward, has been useful for the process of TAS making, but it
suffered from bugs and limitations when interacting during the state loading.
Those limitations and bugs were based on the fact that changing inputs using
the input editor was done by the UI thread, while the rest of the input logic
(reading from movie file or user keyboard, etc.) is performed in the main thread.</p>

<p>Now, all input modifications in the input editor are sent to the main thread.
When they are processed by the main thread, it checks if the modification is
valid (e.g. can’t change a past input). In the meantime, input modifications 
are shown as light gray/dark gray in the input editor. This change allows user
to still submit input modifications during the state loading, without the risk
of doing invalid changes. Also, a rewind cannot be triggered when another one
is happening.</p>

<h3 id="more-automated-detections">More automated detections</h3>

<p>Having to set multiple options before running a game has always been an issue
in libTAS. A few modifications have been made to help users with that:</p>

<ul>
  <li><strong>Autodetect game library folder</strong>: libTAS now detects when a library is
missing to launch the game, then tries to locate this library inside the
game directory. If located, it will fill the <code class="language-plaintext highlighter-rouge">LD_LIBRARY_PATH</code> variable
accordingly, so that users won’t have to manually fill the library path.</li>
  <li><strong>Suggest time-tracking option</strong>: When a game calls a specific <code class="language-plaintext highlighter-rouge">gettime()</code>
function too many times during a single frame, a message is printed on the
terminal indicating the user that the corresponding time-tracking option may
be needed.</li>
  <li><strong>Simplify RAM Search options</strong>: Now it offers three meaningful options that
can be left by default, instead of showing a list of all memory region types</li>
  <li><strong>Autodetect Unity coroutines</strong>: There is a specific hack to make Unity
coroutines to run synchronously from the main thread, but it needed to be
identified for every single Unity engine version. Now it tries to detect the
correct threads from their creation order (which is very fragile, but seems
to work for now). As a note, very recent versions of Unity (e.g.
new Hollow Knight 1.5 version shipping Unity <code class="language-plaintext highlighter-rouge">2020.2.2f1</code>) don’t work with
the deterministic hack, because of how Unity calls thread sync routines. It
basically bypasses libc functions and uses kernel futexes directly.</li>
</ul>]]></content><author><name>Clément Gallet</name></author><summary type="html"><![CDATA[Here is a summary of the main changes in v1.4.3. You can see the full changelog file here.]]></summary></entry></feed>