# Perf Этап 4 — AREA-broadcast: пропуск блоков без игроков ## Что сделано (4a, безопасный вариант) Каждое видимое действие (движение/атака/скилл/чат/спавн) рассылается ближайшим игрокам через `clif_send(... AREA ...)`, который обходит блок-грид карты и для каждого найденного `BL_PC` вызывает `clif_send_sub`. Раньше обходились **все** блоки области ~29×29 клеток, включая блоки, где есть только NPC/предметы/скилл-юниты/мобы и **ни одного игрока**. Добавлена `map_foreachinareaPC()` (src/map/map.c) — специализированный обход AREA только для `BL_PC`, который **пропускает блок, если в нём точно нет игроков** (`block_pc_count[pos]==0`). `block_pc_count` — это точный per-block счётчик `BL_PC|BL_HOM|BL_MER` из mobgrid-подсистемы (инкремент/декремент в `map_addblock`/`map_delblock`, держится в лок-степе со списками блоков, **не** upper-bound). Блок со счётчиком 0 заведомо не содержит игрока → рассылать в нём некому. **Поведенчески-идентично:** собираемый список получателей (`bl_list`) побайтово тот же и в том же порядке, что и у обычного обхода — это чистый «пропусти заведомо пустое», без кэшей и без инвалидации. `clif_send` (src/map/clif.c) для `AREA/AREA_WOS/AREA_WOC/AREA_WOSC` и `AREA_CHAT_WOC` вызывает `map_foreachinareaPC` при включённом флаге, иначе — старый `map_foreachinarea(..., BL_PC, ...)`. ## Флаг `conf/battle/misc.conf`: ``` clif_bcast_pc_grid: 1 // 1 (деф.) = пропускать блоки без игроков; 0 = старый полный обход грида ``` (battle_config; `@reloadbattleconf` для A/B на лету.) ## Где помогает / где нет - **Помогает:** карты с множеством NPC/предметов/мобов, но редкими игроками (поля, города с разрозненными точками) — пустые блоки больше не обходятся при каждой рассылке. - **Не меняет ничего по нагрузке:** плотно набитые игроками карты (WoE-замок) — там в каждом блоке есть игрок, пропускать нечего. Это ожидаемо: пиковая стоимость рассылки в WoE — это сами send()-ы (сеть), а не обход грида (см. этап 5). ## Что СОЗНАТЕЛЬНО НЕ делалось на этом этапе (и почему) - **4a как «кэш списка зрителей» (исходный план):** кэшировать per-bl список fd, кто видит объект, с инвалидацией при пересечении клетки. Отклонено: (1) под WoE все постоянно двигаются → инвалидация-шторм съедает выигрыш; (2) высокий риск десинка (пропустил инвалидацию — соседи не видят действий). Безопасный пропуск пустых блоков даёт часть выгоды без этого риска. - **4b — кэш байт спавн/idle-пакета на bl:** большая поверхность инвалидации (opt1/2/3, option, все поля view_data, гильдия/эмблема/manner/karma/speed/level/dead_sit/head_dir, позиция) → риск показать вновь подошедшему устаревший вид. Выигрыш узкий (статичные сцены в городах), а карта упирается в сеть. Отложено. - **4c — снять 2-й AREA-проход cloth_color:** это ставка на рендер старого клиента 2007 (отдельный пакет `LOOK_CLOTHES_COLOR` может быть обязателен; для моб/пет-спавна 0x7c пакет вообще не несёт cloth_color, т.е. refreshlook там несущий). Невозможно проверить без клиента, риск косметической регрессии. Отложено. ## Как замерить `UA_PERF=1`, профиль `clif_send` / `map_foreachinarea*` self% при `0` vs `1` на карте с NPC/ предметами и умеренным числом игроков. Ожидание: при `1` обход грида в рассылках дешевле на картах с пустыми блоками; на плотных картах разницы нет. ## Чек-лист корректности (тестировщикам) - [ ] Все видят перемещения/атаки/скиллы/чат соседей как и раньше (нет «пропавших» действий). - [ ] Спавн/деспавн мобов, NPC, игроков виден корректно всем в радиусе. - [ ] Города (много вендоров/NPC), поля (мобы+дропы), подземелья — визуально без отличий от `0`. - [ ] WoE/GvG: массовые действия видны всем участникам (поведение как при `0`). - [ ] `0` и `1` дают идентичную картину у клиентов (разница только в CPU). ## Откат `clif_bcast_pc_grid: 0` (+ `@reloadbattleconf` или рестарт map). Сборка чистая; локальный кластер поднимается онлайн, завершается без утечек.