Skip to content

refactor(setall): убрать глобальные буферы из setall (#3807) - #3811

Closed
bylins wants to merge 2 commits into
masterfrom
refactor/do-set-all-strings
Closed

refactor(setall): убрать глобальные буферы из setall (#3807)#3811
bylins wants to merge 2 commits into
masterfrom
refactor/do-set-all-strings

Conversation

@bylins

@bylins bylins commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Третий файл слоя 1 из #3807, после #3809 (кто) и #3810 (трупы).

Найденный баг: пропавшее сообщение

В ветке смены e-mail у офлайнового бессмертного стояло:

if (GetRealLevel(vict) >= kLvlGod) {
    it->second->out += buf1;      // buf1 здесь никто не заполнял
    delete vict;
    continue;
}

buf1 очищается в начале итерации и в этой ветке остаётся пустым — бог не получал ни строчки о том, почему персонаж пропущен. Во всех соседних ветках (заморозка, пароль, ад; онлайн и офлайн) перед этим стоит sprintf(buf1, "Персонаж %s бессмертный!"). Здесь его просто забыли.

Это ровно тот класс ошибок, ради которого затеян слой 1: с общим буфером «забыл заполнить» и «кто-то заполнил раньше» выглядят в коде одинаково.

Новый общий помощник

half_chop копирует остаток через strl_cpy(arg2, temp, kMaxStringLength), а one_argument не проверяет длину вовсе — обоим нужны буферы по 32768 байт. Взять такой буфер локально негде, поэтому в utils/mud_string добавлен:

/// Первое слово строки (в нижнем регистре) и остаток после него -- то же, что делает half_chop,
/// но без фиксированных буферов.
std::pair<std::string, std::string> ChopWord(std::string_view line);

У half_chop в заголовке появилось предупреждение про размер буфера — чтобы следующий не наступил на те же грабли (я наступил, см. второй коммит в #3809).

Шесть тестов в tests/utils.string.cpp: разбиение, нижний регистр, пробелы по краям, одно слово, пустой ввод, многобайтные буквы.

Что ещё в файле

  • сообщения о заморозке, аде, смене пароля и e-mail собираются fmt::format в std::string;
  • разбор аргументов setall — через ChopWord вместо three_arguments в buf/buf1/buf2;
  • sprintf и обращений к глобальным буферам не осталось.

Проверено

Сборка чистая, 679 тестов зелёные (было 673 + шесть новых). На живом проверять: setall <почта> frozen <часы> <причина>, setall <почта> email <новая>, setall <почта> passwd <пароль>, setall <почта> hell <часы> <причина> — и отдельно случай с бессмертным в списке, ради пропавшего сообщения.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH


Правка после ревью: не плодить дубли

Я добавил в mud_string свой ChopWord — и зря: строковый аналог half_chop уже есть, это utils::ExtractFirstArgument (utils_string.h:150). Свой помощник и тесты к нему убраны, разбор идёт через готовую функцию.

Отличия учтены на месте вызова: ExtractFirstArgument не понижает регистр (а one_argument понижает) и оставляет в остатке ведущие пробелы. Поэтому слова проходят через native_text::to_lower, остаток — через TrimLeft. Регистр тут важен не для сравнений (isname и IsAbbr и так без учёта регистра), а для почты: она сверяется с player_table подстрокой, то есть с учётом регистра.

У half_chop в заголовке осталось предупреждение про размер буфера с указанием, чем пользоваться вместо него.

bylins and others added 2 commits August 29, 2026 19:25
Третий файл слоя 1. Все сообщения бога собирались в глобальных buf1 и buf2,
разбор аргументов -- в buf/buf1/buf2 через three_arguments.

Заодно чинится пропавшее сообщение. В ветке смены e-mail у офлайнового
бессмертного стояло

    if (GetRealLevel(vict) >= kLvlGod) {
        it->second->out += buf1;

-- но buf1 в этой ветке никто не заполнял: он очищался в начале итерации и
оставался пустым. Бог не получал ни строчки о том, почему персонаж пропущен.
Во всех соседних ветках перед этим стоит sprintf с текстом "Персонаж %s
бессмертный!". Теперь текст на месте.

Разбор аргументов переведён на ChopWord -- новый общий помощник в mud_string:
первое слово в нижнем регистре и остаток, без фиксированных буферов. Он заменяет
half_chop там, где буфер нужного размера взять негде: half_chop копирует остаток
с оглядкой на kMaxStringLength, а one_argument вообще не проверяет длину. У
half_chop в заголовке появилось предупреждение об этом.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
…мощника

Строковый аналог half_chop в проекте уже есть -- utils::ExtractFirstArgument
(utils_string.h:150, "аналог one_argument для string"). Свой ChopWord был лишним
дублем, убран вместе с тестами на него.

Отличия учтены на месте вызова: ExtractFirstArgument не понижает регистр (а
one_argument понижает) и оставляет в остатке ведущие пробелы, поэтому слова
проходят через native_text::to_lower, а остаток -- через TrimLeft. Регистр важен
не для сравнений, а для почты: она сверяется с player_table подстрокой.

У half_chop в заголовке осталось предупреждение о размере буфера и указание, чем
пользоваться вместо него.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
@bylins

bylins commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

Собрано вместе с остальными в #3813 — там все три темы одним PR, потому что ExtractFirstArgument из третьего нужен первым двум. Этот закрываю.

@bylins bylins closed this Aug 29, 2026
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.

1 participant