Skip to content

Strip surrounding whitespace from player names#1526

Open
Rainyan wants to merge 16 commits intoNeotokyoRebuild:masterfrom
Rainyan:bug/empty-name
Open

Strip surrounding whitespace from player names#1526
Rainyan wants to merge 16 commits intoNeotokyoRebuild:masterfrom
Rainyan:bug/empty-name

Conversation

@Rainyan
Copy link
Copy Markdown
Collaborator

@Rainyan Rainyan commented Nov 27, 2025

Description

Strip surrounding whitespace from player name variables name (Steam name), neo_name, and neo_clantag.

Toolchain

  • Windows MSVC VS2022

Linked Issues

@Rainyan Rainyan changed the title Strip whitespace from player names Strip surrounding whitespace from player names Nov 27, 2025
@Rainyan Rainyan requested a review from a team November 30, 2025 00:09
@AdamTadeusz
Copy link
Copy Markdown
Contributor

image image

There's a disconnect between what the settings page tells us our display name is vs what our display name actually is.

AdamTadeusz
AdamTadeusz previously approved these changes Dec 1, 2025
@AdamTadeusz AdamTadeusz requested a review from a team December 1, 2025 13:27
sunzenshen
sunzenshen previously approved these changes Dec 2, 2025
@Rainyan Rainyan marked this pull request as draft December 8, 2025 05:56
@Rainyan Rainyan added the Current WIP Currently working on it label Mar 17, 2026
@Rainyan Rainyan dismissed stale reviews from sunzenshen and AdamTadeusz via 200bee3 March 18, 2026 00:57
@Rainyan Rainyan force-pushed the bug/empty-name branch 2 times, most recently from 200bee3 to 0b647c4 Compare March 18, 2026 01:00
@Rainyan
Copy link
Copy Markdown
Collaborator Author

Rainyan commented Mar 18, 2026

There's a disconnect between what the settings page tells us our display name is vs what our display name actually is.

This should be now fixed.

@Rainyan Rainyan requested a review from nullsystem March 18, 2026 01:18
@Rainyan Rainyan marked this pull request as ready for review March 18, 2026 01:19
@Rainyan Rainyan marked this pull request as draft March 18, 2026 01:32
@Rainyan Rainyan marked this pull request as ready for review March 18, 2026 02:41
@Rainyan Rainyan requested review from a team and removed request for AdamTadeusz and sunzenshen March 18, 2026 02:42
@Rainyan Rainyan removed the Current WIP Currently working on it label Mar 18, 2026
@AdamTadeusz
Copy link
Copy Markdown
Contributor

AdamTadeusz commented Mar 18, 2026

So to clarify, Q_StrTrim is insufficient because we want to allow one whitespace at the end of the string? But why do we want to allow one whitespace at the end of the string?

Never mind I see this gets applied in real time, cool

(edit) one problem with that I guess is that if I want multiple spaces in the middle of my name (which technically is allowed), I have to write the name without those spaces and then move my cursor back to the middle and then put all those spaces in.
image

@AdamTadeusz
Copy link
Copy Markdown
Contributor

AdamTadeusz commented Mar 18, 2026

One thing that confuses me is why whenever I place a breakpoint in say V_IsMeanSpaceW where the return value is set to true, and enter a character that causes that breakpoint to be hit, a breakpoint in VarTrimmer inside the block called when predicate() returns true still isn't hit

8mb.video-uPg-TJJCbzYn.mp4

@AdamTadeusz
Copy link
Copy Markdown
Contributor

AdamTadeusz commented Mar 18, 2026

ok i figured it out its for the first character only, but still a bit confused

AdamTadeusz
AdamTadeusz previously approved these changes Mar 18, 2026
@Rainyan Rainyan requested a review from AdamTadeusz March 18, 2026 12:14
@AdamTadeusz
Copy link
Copy Markdown
Contributor

image

This is not an issue with this pr specifically but more with NeoUI::TextEdit, where large unicode characters take up more space than standard characters, so in this example the string ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą takes up double the number of characters as aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa and so the name is invalid, but the TextEdit input doesn't stop me from entering more characters earlier.

Nagrywanie.ekranu.2026-03-18.124512.mp4

Anyway, good to see that it doesn't cause any problems in the end 👍

AdamTadeusz
AdamTadeusz previously approved these changes Mar 18, 2026
@Rainyan Rainyan requested review from a team and removed request for nullsystem March 18, 2026 14:00
Rainyan added 12 commits March 30, 2026 16:11
Block all bad characters
NeoName and NeoClantag wchar conversions via g_pVGuiLocalize->ConvertANSIToUnicode
will return "#empty" for an empty input. In those cases, move the null
terminator to the beginning of the string, so that we get:

L"#empty" -> L""

because we don't want to display the value "#empty" for the user in the
UI.
MAX_PLACE_NAME_LENGTH -> MAX_PLAYER_NAME_LENGTH
After the VarTrimmer input is moved one position to the left, the
loop index and the loop condition index must be decremented by one to
compensate for it.

This happened to work previously by coincidence in the IMGUI loop,
since it would fix 1 trailing character at a time before incorrectly
exiting the loop, and continue the work on the next UI draw call. But
indeed the correct behaviour would be to process the whole input in one
loop.
@Rainyan
Copy link
Copy Markdown
Collaborator Author

Rainyan commented Mar 30, 2026

Rebased to master and addressed the bugs found by @sunzenshen

Also fixed a case where the char -> wchar conversion via the vguilocalize utility could return "#empty" for empty values, and made those actually print an empty "" string in the UI instead.

New changes (aside from the rebase):

  • fa79e0a - Review feedback: Fix loop idx OBOE after memmove
  • 7716e9c - Review feedback: Fix typo in szSteamName alloc size
  • 2b16761 - Review feedback: Remove redundant iTextSelCur assignment
  • 39eb888 - Fix empty ret vals from vguilocalize

@Rainyan Rainyan requested a review from sunzenshen March 30, 2026 13:19
sunzenshen
sunzenshen previously approved these changes Mar 31, 2026
ConVarRef cvarRef(cvar);
V_strcpy_safe(mutStr, cvarRef.GetString());

if (V_strlen(cvarRef.GetString()) >= STR_LIMIT_SIZE)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional nit:
Just to sanity check, but is it intended that Q_UnicodeRepair will be called only when the string is over STR_LIMIT_SIZE?

I did the see the SDK comment:

// Repair invalid Unicode strings by dropping truncated characters and fixing improperly-double-encoded UTF-16 sequences.
// Unlike conversion functions which replace with '?' by default, a repair operation assumes that you know that something
// is wrong with the string (eg, mid-sequence truncation) and you just want to do the best possible job of cleaning it up.
// You can pass a REPLACE or FAIL policy if you would prefer to replace characters with '?' or clear the entire string.
// Returns nonzero on success, or 0 if the policy is FAIL and an invalid sequence was found.

And I suppose this should only be called when something is known to be wrong, but is the string size the only error case we know of in this context?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't remember why that length check is there, but yeah we should probably just always call that function.

static void NeoConVarFixPrintable(IConVar *cvar, const char *, float)
{
// prevent reentrancy
static bool bStaticCallbackChangedCVar = false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional nit because to my understanding, only 1 translation unit from cdll_client_int.cpp is using NeoConVarFixPrintable, but if cdll_client_int.h is #included in other contexts, wouldn't this static get duplicated?

Would an inline have accomplished the same intentions?

template <int STR_LIMIT_SIZE>
    requires (STR_LIMIT_SIZE > 0)
inline void NeoConVarFixPrintable(IConVar *cvar, const char *, float)
{ ... }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh whoops, you're right. For some reason I assumed the template with the same STR_LIMIT_SIZE would resolve to the same definition but that's obviously not the case here.


if (hasBadCharInPos || hasDoubleBlankInPos)
{
std::wmemmove(&input[i], &input[i + 1], zeroIdx-i);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional nit:

supposedly Q_memmove is the equivalent Valve utility, e.g.

Q_memmove(&input[i], &input[i + 1], (zeroIdx - i) * sizeof(wchar_t));

@Rainyan
Copy link
Copy Markdown
Collaborator Author

Rainyan commented Mar 31, 2026

Also fixed some instances where the empty string (#empty) could be rendered in the scoreboard in place of a Steam name, or the empty clantag, in df9f1a9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IFF breaks when a player has a name made up of space characters

4 participants