# Боты: что сделано и как этим пользоваться Сборка от 2026-08-25 (пак `server_interlude.zip`). Население 1–76 с настоящей прокачкой, всё включено по умолчанию. ## Что в паке **Геодата** — 172 региона `.l2j` уже лежат в `game\data\geodata`, `PathFinding = 2` включён. Боты и мобы обходят стены и ходят по реальному рельефу. **5000 персонажей, уровни 1–76, 34 зоны** (замер: ~22% одного слабого ядра на все 5000, масштаб почти бесплатный) — от стартовых полей всех рас (Talking Island, Elven Forest, Shadow Land, Orc Lands, Dwarven Valley) через Wasteland, Cruma, Execution Grounds, Sea of Spores, Plains of Glory до Blazing Swamp, Wall of Argos, Ketra и Varka. У каждого — ник, пол, внешность, класс из 11 архетипов (гладиатор, паладин, разрушитель, кинжальщики, лучники, три школы магов, бишоп) и шмот по грейду. Стартовые уровни раскиданы по всей кривой, так что мир населён сразу. **Настоящая прокачка.** Боты получают опыт с реально убитых мобов (реальные exp-значения мобов из датапака, рейт `FakePlayerXpRate`, по умолчанию x3). Уровень и опыт хранятся в таблице `fake_player_progress` и переживают рестарт. 8 тиров (1–14, 15–24, 25–34, 35–44, 45–54, 55–63, 64–71, 72–76): при переходе тира бот пишет в чат «апнулся, ушёл за шмотом», исчезает и через 1–3 минуты появляется в зоне своего нового уровня — с новой профой (варриор → глад → дуэлист) и новым грейдом шмота (NG → D → C → B → A → S). Кап 76. То есть встреченный на Talking Island новичок через пару дней реально будет фармить в Cruma, а потом в Blazing Swamp. **Четыре характера** (параметр `fpcPersonality`): - `ganker` (~25%) — фармит и нападает на игроков в радиусе 1000, кидает дерзкую реплику. Ганкают на любом уровне, включая стартовые поля — но только там, куда бот такого уровня и расы мог реально прийти. - `pkk` (~10%) — охотник на ПК: белых не трогает, но нападает на фиолетовых (PvP-флаг) и красных (карма). Убил ганкера у новичков — жди комментарий про правосудие. - `helper` (~15%) — видит твой бой — прибегает и помогает, комментирует. - `neutral` (~50%) — мирно фармит и болтает. Все, кроме ганкеров, тоже сами бьют мобов (иначе бы не качались). **Правдоподобность появления**: стартовые локации расовые — на Talking Island качаются только люди, в Elven Forest эльфы, у орков орки и т.д. (бот другой расы «не мог туда прийти»). С 15-го уровня все смешиваются на континенте. Уровень бота всегда соответствует зоне. **Торговля.** Периодически бот «уходит в город» (по уровню и расе: новички — в свою деревню, 40+ — Гиран/Орен/Аден...), садится и открывает лавку: скупку — если ему «нужно что-то», или продажу — если перед этим успешно нафармил. Раз в 3 минуты кричит зазывалку в торговый канал (текст генерирует LLM). Через час лавка закрывается, бот возвращается на спот, следующая торговля через ~2–2.5 часа. Настройки в `FakePlayers.ini`: `FakePlayerTrading`, `FakePlayerTradeDuration`, `FakePlayerTradeCooldown`, `FakePlayerTradeShoutInterval`, `FakePlayerTradeChance`. Лавки декоративные: купить/продать им ничего нельзя (это NPC без настоящего инвентаря) — но выглядят и кричат как живые. **Мир живёт без тебя**: `GridsAlwaysOn = True` — AI работает во всех регионах, боты фармят и качаются, даже когда тебя нет рядом. Это дороже по CPU; если сервер начнёт тормозить — выключи в `General.ini`, тогда качаться будут только зоны рядом с тобой. **LLM-чат через Ollama.** Боты пишут по-русски: тонт при ганге, комментарий при помощи, бытовой трёп когда ты рядом, ответ если ты что-то сказал в общий чат возле них (шанс 40%), ответ в личку (шёпот `"ник текст`). Если Ollama не запущена — молча откатываются на шаблонные ответы из `FakePlayerChatData.xml`, сервер работает как обычно. ## Рынок, титулы, гербы **Лавки торгуют настоящим лутом.** Боты подбирают дроп со своих убийств (свой лут, чужой не трогают) и идут в город, только когда действительно есть что продать; в лавку выставляются реальные вещи из инвентаря по цене от справочной ±. Никаких выданных из воздуха товаров и никакого лимита — торгуют те, кто нафармил. **Название лавки собирается из частей** (пулы `store_goods` / `store_price` / `store_mood`): «соски дёшево налетай», «C грейд по рынку», «дроп оптом не торгуюсь» — тон зависит от характера. Подпись теперь реально видна: раньше не хватало broadcast'а `PrivateStoreMsgSell`. **Титулы вместо PK/PKK.** Над ником — то, что пишут живые игроки: «ищу клан», «куплю адену», «afk», «Гиран», «рб хантер», у большинства пусто. Характер больше нигде не светится. **Гербы кланов и альянсов** генерируются процедурно (DXT1 DDS 16×12 и 8×12, как требует клиент — 224 и 176 байт при лимитах 256/192): шесть геральдических стилей (полосы, четверти, шеврон, рамка, диагональ, шахматка) и восемь палитр, детерминированно от названия клана. 150 кланов сведены в ~19 альянсов, у каждого свой герб. Сид `db_installer\sql\spp_crest_seed.sql` применяется автоматически (entrypoint теперь накатывает все `spp_*.sql`). ## Мир только из headless-игроков (текущая схема) NPC-боты выключены (`FakePlayerProgression = False`), население — 500 headless-игроков (`FakePlayerHeadlessCount`), выбранных случайно из тех же 5000 сид-персонажей, то есть с разбросом по всем уровням 1–76. Каждый расселяется в зону по своему уровню и расе (та же таблица зон, что была у NPC — она грузится всегда, даже когда NPC-население отключено). Стоковый бот Evi из поставки Mobius отключён. Хочешь другое число — правь `FakePlayerHeadlessCount` и пересобирай образ. Замер: 500 headless на слабом ядре песочницы — 3.2% CPU, +0.5 ГБ RAM; на нормальной машине запас большой, но помни, что Player в бою дороже NPC. Вернуть гибрид (NPC-статисты + элитные headless) — поставить `FakePlayerProgression = True` и уменьшить `FakePlayerHeadlessCount`: тогда headless берут только «хвост» сид-персонажей, а остальные живут как NPC. ## Headless-игроки (настоящая пати) — прототип `FakePlayerHeadlessCount` в `FakePlayers.ini` (по умолчанию 30) поднимает N ботов не как NPC, а как настоящие `Player`-инстансы без клиента — поднятые из тех же сид-персонажей (берутся старшие charId, прогрессия их не трогает). Они фармят у Гирана. Ключевое: **их можно позвать в настоящую пати** — жмёшь invite, бот через 1–2 сек сам принимает, появляется окно группы, идёт опыт, боты держатся рядом с лидером и ассистят его цель; после смерти встают через 15 сек. Это цена «быть настоящим игроком»: для движка они игроки, потому что это класс `Player`, а не NPC с флагом. **Весь функционал NPC-ботов перенесён на headless.** Они берут свою личность из того же сида (`FakePlayerProgression.xml`): характер (ganker/pkk/helper/neutral), раса, клан, домашняя зона. И дальше умеют всё то же самое: - **речь**: те же швы + LLM с той же персоной; тонты при ганге, реплики ПКК, ассист, бытовой трёп, левел-ап, прощание при переезде; - **понимание**: шёпот и общий чат проходят через тот же разбор интентов — оскорбил ганкера, он нападёт; попросил помощи, побежит; спросил «что нового» — расскажет слух; - **память и слухи**: помнят, кто их убивал и кто помогал; смерть headless-бота видят соседние боты и разносят историю с искажением; - **прогрессия настоящая**: они получают реальный опыт с мобов (они же игроки), при переходе тира сами прощаются и телепортируются в зону своего уровня — по той же таблице зон, что у NPC; - **пати между собой**: соклановцы поблизости собираются в **настоящие** L2-пати (не имитация); - **дашборд**: видны на карте отдельным значком (★, обведены золотым), фильтруются как обычные боты. **Что они умеют как игроки** (добавлено после первого прототипа): - **клан**: при спавне восстанавливается членство из БД — крест над ником, участие в клановых войнах; - **торговля**: раз в 0.5–1.5 часа бот телепортируется на площадь Гирана, получает товар (соски, D-грейд), выставляет **настоящую приватную лавку** с ценником и садится на 20–60 минут. У такой лавки реально можно купить — это полноценный `PrivateStoreType.SELL`, а не декорация как у NPC-торговцев; - **PvP**: если рядом игрок или другой headless из клана-врага — атакует, со всеми штатными последствиями (флаг, карма, PvP-счётчик). **Замер (песочница, 2 слабых ядра, без геодаты, изолированно от NPC-ботов):** | headless | CPU | RAM | |---|---|---| | 0 | 1.3% | 1.81 ГБ | | 500 | 3.2% | 2.29 ГБ | То есть ~1 МБ и почти ноль CPU на одного простаивающего headless-игрока. Но честные оговорки: замер без геодаты (pathfinding выключен) и в основном на фарме — активный бой у Player-инстанса дороже NPC (пересчёт статов, тики эффектов, апдейты пати, броадкаст пакетов), так что под нагрузкой с геодатой цена вырастет. Вывод: **30–100 headless-игроков рядом с 5000 NPC — комфортно; тысячи headless — нет** (это подтверждает гибридную архитектуру). И: авто-принятие пати написано по образцу штатного accept, но вживую с клиентом я его не проверял — это прототип, первым делом протести окно группы у себя. ## Речь, память, слухи **Композитные фразы.** Реплика собирается из кусочков, а характер решает, какие кусочки вообще войдут: - `game\data\FakePlayerPools.xml` — 26 пулов по 12 кусочков (приветствия, обращение по нику, слово-паразит, угроза, насмешка, похвальба, предложение помощи, зов в пати, бытовуха, жалоба, встречный вопрос, хвосты-смешки и т.п.). Пул с суффиксом характера (`hello.helper`, `threat.pkk`) перекрывает базовый. - `game\data\FakePlayerPhrases.xml` — шаблоны сборки: ``. То есть ганкер никогда не здоровается, а сразу насмехается; хелпер здоровается развёрнуто и добавляет встречный вопрос; ПКК отвечает сухо. Из тех же частей выходит «прив, {player} чё как» у дружелюбного и «слышь {player} ща будет больно кек» у пкшера. Если для ключа шаблона нет — используется плоский шов из `FakePlayerChatLines.xml`, так что старые ключи продолжают работать. Проверить руками: на дашборде блок «Генератор фраз» — вводишь ключ и характер, получаешь 8 разных сборок. **Плоские швы** (`game\data\FakePlayerChatLines.xml`): 194 реплики в 14 событийных швах со слотами `{target}/{player}/{boss}/{town}/{level}/{msg}` — редактируются без пересборки. Анти-повтор: каждый бот помнит свои последние 12 реплик и не повторяется. **Память** (`fake_player_memory`): бот помнит, кто его убивал (обида) и кто помогал добить его моба (благодарность). При встрече узнаёт («опа, а вот и обидчик»), LLM-разговоры тоже пишутся в память. **Слухи** — порт системы из «Округи»: смерть бота видят соседние боты (свидетели), истории гуляют между ботами при встречах с искажением (уверенность падает, пересказы копятся, масштаб растёт: «гангнул» → «вырезал всех на точке» → «пол сервера в страхе держит»). Рассказывая тебе, бот выдаёт источник хеджем: «сам видел как ты…» / «говорят ты…» / «брешут будто ты…» / «уже легенды ходят как ты…». Стоя рядом с двумя ботами, можно подслушать сплетню о себе. Всё в `fake_player_rumor`, переживает рестарт, и всё это скармливается LLM в персону (с пометкой «пересказ N раз, можешь ошибаться»). ## Группы, рейды, олимпиада **Сквады.** Ганкеры и охотники на ПК ходят группами по 2–4 (свой клан, свой уровень, своя раса): лидер ведёт маршрут, остальные держатся рядом и вместе входят в бой (соседние фейки и так ассистят друг другу в радиусе 600). Итого ~500 бродячих групп: ганг встречается пати, и ответка от ПКК тоже приходит пати. **Рейды на боссов.** Каждые 30–90 минут собирается пати из 5 ботов 60+ и идёт убивать живого рейд-боссa (55–80 lvl): телепорт к боссу («со стороны» выглядит как приход группы), боевой клич в чат, бой до смерти босса или 25 минут, потом расходятся по спотам. В логе: `Raid event started/finished`. Гранд-боссы (Баюм и т.п.) не трогаются. **Олимпиада — иллюзия, честно.** Настоящие бои олимпиады требуют персонажей-игроков, NPC-боты в них участвовать не могут — это фундаментальное ограничение. Что сделано вместо: 60 ботов записаны в нобли с очками/статистикой боёв, 12 из них — действующие Герои (по классам). Списки ноблей и героев в игре настоящие. Чего нет: самих матчей и ротации героев по месяцам (могу добавить «виртуальную ротацию» очков позже). ## Кланы, войны, холлы, замки (pre-seed) 12 бот-кланов в базе (RedSyndicate и GopStop — пкшеры, KarmaPolice и NightWatch — охотники на ПК, Academka — новички, IronPact/OldSchool — хай-энд...). ~85% ботов состоят в кланах и носят клан-теги; все 200 существуют и как офлайн-персонажи, так что списки членов кланов в игре настоящие. Между кланами прописано 8 взаимных войн. 30 из 34 аукционных клан-холлов заняты бот-кланами (аренда оплачена), 4 свободны для тебя. Замки Глудио, Дион, Гиран и Аден принадлежат бот-кланам (кресты над городами). **Война с бот-кланом работает по-настоящему**: объяви войну (например, RedSyndicate) — и каждый бот этого клана при встрече будет нападать на членов твоего клана, с боевыми выкриками. Осады замков ботами пока не отыгрываются. Сид идемпотентный (`db_installer\sql\spp_clan_seed.sql`), применяется автоматически при старте login-контейнера; занятые игроком холлы не трогает. ## Включение Ollama 1. Поставь Ollama: https://ollama.com/download 2. `ollama pull gemma3` 3. Ollama должна слушать на 127.0.0.1:11434 (по умолчанию так и есть). Всё. Сервер сам начнёт ходить в неё. Модель, язык, тайминги и шансы — в `game\config\Custom\FakePlayers.ini`, секция «SPP additions». ## Настройка `game\config\Custom\FakePlayers.ini`: - `FakePlayerXpRate = 3` — скорость прокачки ботов (реальный опыт мобов × рейт). - `FakePlayerProgression = True` — вся система прокачки; False = статичное население. - `FakePlayerAggroPlayers = True` — ганкеры нападают на игроков. False = мирные боты. - `FakePlayerAmbientChatChance / CombatChatChance / LocalChatReplyChance` — болтливость. - `FakePlayerLlmModel` — любая модель Ollama (gemma3, qwen3, llama3.1...). Сбросить прогресс всех ботов: `DROP TABLE fake_player_progress;` в базе — при следующем старте пересоздастся со стартовыми уровнями. Своих персонажей добавлять в `game\data\FakePlayerProgression.xml` (секция `character`: id, имя, характер, стартовый уровень) — но для нового id нужны и 8 тир-шаблонов в `game\data\stats\npcs\custom\fpc_spp_*.xml` (id = 82000 + (charId−1)×8 + тир). Проще попросить меня перегенерировать население с нужными параметрами. ## Что изменено в исходниках (src_mobius_interlude.zip) Новые файлы: - `gameserver/managers/FakePlayerLlmService.java` — асинхронный клиент Ollama (без зависимостей, семафор на 2 запроса, санитизация ответов). - `gameserver/managers/FakePlayerAiTaskManager.java` — «мозг»: тик раз в 5 сек, тонты при ганге, ассист и фарм для не-агрессивных, бытовой чат. - `gameserver/managers/FakePlayerProgressionManager.java` — прокачка: опыт с киллов, тиры, миграция между зонами, движение по точкам зоны, персист в БД. Правки: - `FakePlayerChatManager.java` — LLM-путь с фолбэком на паттерны, `manageLocalChat`/`manageEventChat`/`broadcastToNearby`, персона бота из шаблона. - `FakePlayersConfig.java` — новые ключи конфига. - `Attackable.java` — хук начисления опыта боту при убийстве моба. - `GameServer.java` — старт менеджеров. - `data/scripts/handlers/chat/channels/ChatGeneral.java` — реакция ботов на общий чат. Данные генерируются скриптом (1600 шаблонов в `fpc_spp_00..07.xml`, зоны/опыт/персонажи в `FakePlayerProgression.xml`). Таблица опыта построена из реальных exp-значений мобов датапака: уровень ≈ 60 убитых мобов своего уровня. Пересборка: `ant` из корня `L2J_Mobius_CT_0_Interlude` (нужны JDK 25 и Ant). ## Проверено в песочнице Полный цикл на тестовом рейте x1000: за 2,5 минуты 192 из 200 ботов получили опыт с реальных киллов, +2066 уровней суммарно, миграции между зонами и сохранение в БД отработали, 0 исключений в логе. ## Ограничения текущей версии Уровень бота в бою определяется тиром (статы шаблона), а не точным уровнем из БД — внутри тира бот дерётся одинаково. Хилеры-helper-ы бьют моба, а не хилят тебя. Ганкеры бросают погоню, если ты убежал далеко от их зоны. Пати с ботами собрать нельзя — они NPC; управляемые пати-боты — следующий большой этап.