<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>editor on stillcooking.dev</title>
    <link>https://stillcooking.dev/en/tags/editor/</link>
    <description>Personal portfolio and technical notes</description>
    <generator>Hugo</generator>
    <language>en-US</language>
    
    <copyright>© 2026 stillcooking.dev — CC BY 4.0, https://creativecommons.org/licenses/by/4.0/</copyright>
    <lastBuildDate>Thu, 09 Jul 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://stillcooking.dev/en/tags/editor/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>A Blueprint node tooltip stops at the first @param</title>
      <link>https://stillcooking.dev/en/topics/unreal-engine/editor-tooling/blueprint-node-tooltip-param-truncation/</link>
      <pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate>
      
      <guid isPermaLink="true">https://stillcooking.dev/en/topics/unreal-engine/editor-tooling/blueprint-node-tooltip-param-truncation/</guid>
      <description>The tooltip generator cuts the function comment off at the first @param and moves everything below it onto the individual pin tooltips. It affects every BlueprintCallable node, and it changes where you have to put warnings in your own API exposed to Blueprints.</description>
      <content:encoded><![CDATA[<p>A Blueprint node&rsquo;s tooltip shows the function comment only up to the first <code>@param</code>. Parameter descriptions, return value documentation, warnings attached to one specific argument: everything below that point ends up on the individual pin tooltips. Nobody checks those tooltips until they already know what they&rsquo;re looking for.</p>
<p>It comes down to how the tooltip generator splits the comment. That behavior affects every BlueprintCallable node, in the engine and in every plugin.</p>
<h2 id="the-symptom-nine-pins-a-two-sentence-tooltip">The symptom: nine pins, a two-sentence tooltip</h2>
<p><code>Set Timer by Event</code> is the textbook case. The function comment warns that a time less than or equal to zero clears the timer instead of setting it (<code>Engine/Classes/Kismet/KismetSystemLibrary.h:723</code>):</p>
<div class="highlight" data-lang="cpp">
  <button type="button" class="code-copy" data-code-copy data-label="Copy" data-copied="Copied!" aria-label="Copy code to clipboard">Copy</button><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Set a timer to execute delegate. Setting an existing timer will reset that timer with updated parameters.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param Event   Event. Can be a K2 function or a Custom Event.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param Time    How long to wait before executing the delegate, in seconds.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *                Setting a timer to &lt;= 0 seconds will clear it if it is set.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * ...
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span></span></span></code></pre></div></div>
<p>The node tooltip itself reads, in full:</p>
<blockquote>
<p>Set a timer to execute delegate. Setting an existing timer will reset that timer with updated parameters.</p>
<p>Target is Kismet System Library</p>
</blockquote>
<figure class="prose-figure">
  <img src="/screens/tooltip-node-truncated.png" alt="Tooltip of the Set Timer by Event node: two sentences of description and the line Target is Kismet System Library, with no mention of the behavior when Time &lt;= 0" loading="lazy" /></figure>
<p>The sentence about <code>&lt;= 0</code> shows up when you hover the <code>Time</code> pin, and nowhere else:</p>
<figure class="prose-figure">
  <img src="/screens/tooltip-pin-time.png" alt="Tooltip of the Time pin on the same node: the full description, including the sentence about clearing the timer when the value is less than or equal to zero" loading="lazy" /></figure>
<p>I wrote up the consequences of this particular case separately in <a href="/en/topics/unreal-engine/gameplay-framework/set-timer-by-event-time-zero">Set Timer by Event with Time = 0.0 never fires</a>. What interests me here is the mechanism, because it affects far more than just this one node.</p>
<h2 id="the-cause-split-with-nullptr-on-the-right">The cause: <code>Split</code> with <code>nullptr</code> on the right</h2>
<p>The node tooltip comes from <code>ObjectTools::GetDefaultTooltipForFunction</code> (<code>Editor/UnrealEd/Private/ObjectTools.cpp:5396</code>), and the whole decision fits in two calls:</p>
<div class="highlight" data-lang="cpp">
  <button type="button" class="code-copy" data-code-copy data-label="Copy" data-copied="Copied!" aria-label="Copy code to clipboard">Copy</button><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Strip off the doxygen nastiness
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="k">const</span> <span class="n">FString</span> <span class="nf">DoxygenParam</span><span class="p">(</span><span class="n">TEXT</span><span class="p">(</span><span class="s">&#34;@param&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">FString</span> <span class="nf">DoxygenReturn</span><span class="p">(</span><span class="n">TEXT</span><span class="p">(</span><span class="s">&#34;@return&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Tooltip</span><span class="p">.</span><span class="n">Split</span><span class="p">(</span><span class="n">DoxygenParam</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Tooltip</span><span class="p">,</span> <span class="k">nullptr</span><span class="p">,</span> <span class="n">ESearchCase</span><span class="o">::</span><span class="n">IgnoreCase</span><span class="p">,</span> <span class="n">ESearchDir</span><span class="o">::</span><span class="n">FromStart</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Tooltip</span><span class="p">.</span><span class="n">Split</span><span class="p">(</span><span class="n">DoxygenReturn</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Tooltip</span><span class="p">,</span> <span class="k">nullptr</span><span class="p">,</span> <span class="n">ESearchCase</span><span class="o">::</span><span class="n">IgnoreCase</span><span class="p">,</span> <span class="n">ESearchDir</span><span class="o">::</span><span class="n">FromStart</span><span class="p">);</span></span></span></code></pre></div></div>
<p><code>Split</code> with the result written back to <code>LeftString</code> and <code>nullptr</code> in place of <code>RightString</code> truncates the text at the first match. The right-hand side is computed and thrown away. The comment “strip off the doxygen nastiness” describes the intent precisely: the Doxygen tags were treated as noise and removed together with the content they describe.</p>
<p>Everything else follows from that one decision. Parameter descriptions take a separate route to the individual pin tooltips (<code>ObjectTools.cpp:5452</code>), and <code>@see</code> and <code>@note</code> survive the cut and render as <code>See:</code> and <code>Note:</code>, but only when they appear above the first <code>@param</code>.</p>
<h2 id="what-to-do-about-it">What to do about it</h2>
<p><strong>Reading someone else&rsquo;s nodes:</strong> if a node tooltip looks suspiciously thin for the number of pins, the documentation is most likely on the pins. Hovering a pin takes a second and routinely reveals information that was missing from the node tooltip.</p>
<p><strong>Exposing your own API to Blueprints</strong> (which covers every plugin with <code>UFUNCTION(BlueprintCallable)</code>):</p>
<div class="callout callout--warning">
  <div class="callout__title">Warning</div>
  Everything the user needs to know <strong>before</strong> wiring up the node has to sit in the description block above the first <code>@param</code>: edge cases, values that invalidate the call, initialization order requirements. A sentence attached to a parameter is technically correct documentation and effectively invisible: the user will not see it until they start hunting for the cause of a bug, which is one step too late.
</div>

<div class="callout callout--tip">
  <div class="callout__title">Tip</div>
  An <code>@note</code> placed above the parameter list renders as <code>Note:</code>. That is the simplest way to make such a warning stand out while keeping the comment compatible with Doxygen.
</div>

<h2 id="when-this-matters">When this matters</h2>
<p>On a node with two pins, not much. The whole description fits in the opening sentence anyway.</p>
<p>The stakes rise with the number of parameters, and with the number of values that are technically valid but mean something other than what the user assumes: zero for “cancel,” a negative value for “no limit,” an empty name for “use the default.” That kind of knowledge belongs next to the parameter by definition — and the text next to the parameter is exactly what the node tooltip will not show.</p>
<p>There&rsquo;s one more consequence for plugin authors: a user who falls into that trap despite a correctly written comment will file it as a documentation bug. The comment will be right where it belongs, and the report will still be justified.</p>
]]></content:encoded>
      
    </item>
    
  </channel>
</rss>
