AI-рецепт по боту с чтением списка сущностей из памяти

Короткий рецепт с рекомендациями для простого reader-а памяти, который показывает сущности из другого процесса.

Чтение списка сущностей из памяти для бота

ПолеЗначение
СложностьСредняя
ПримерДемонстрация радара для Assault Cube, которая читает данные сущностей из памяти и показывает их в окне Blazor.
Конечная цельПоказать живой список сущностей из другого процесса с именами, позициями, здоровьем и другими похожими полями.
Ключевые технологииMemory API, RemoteMemoryObject, память модуля, окно Blazor

Когда использовать

  • Вы уже знаете целевой процесс и модуль.
  • У вас есть offsets для указателя игрока, указателя списка сущностей, количества сущностей и нужных полей.
  • Список сущностей достаточно небольшой, чтобы обновлять его по таймеру.
  • Задача — просмотр данных, радар, отладка или простой вспомогательный UI.

Пример

Assault Cube 1.3.0.2 Radar — это очень маленький публичный pack с одной аурой CsharpScript. На странице pack он описан как демо Memory API вместе с BlazorWindow для отрисовки радара.

Демо радара Assault Cube

Собрать один снимок списка

Входы операции — уже открытый IProcess, абсолютный адрес массива указателей, число элементов и layout сущности для конкретной версии цели. До обхода задайте допустимый размер списка для этой программы; число из памяти не должно бесконтрольно определять объём работы. Для x64-цели массив адресов можно прочитать одной операцией:

csharp
static ulong[] ReadEntityAddresses(
    EyeAuras.Memory.IProcess process, long arrayAddress, int count)
{
    return process.Memory.Read<ulong>(arrayAddress, count);
}

Результат — count значений ulong, не count байт. Для x86 нужен uint, а не зависящий от хоста nint. Если известен RVA поля, сначала прибавьте базу модуля. Если поле хранит указатель на массив, сначала прочитайте этот указатель: адрес поля и адрес массива — разные входы.

Затем для каждого ненулевого адреса прочитайте известные поля через Read<T> либо целую unmanaged-структуру. Для строки задайте реальную кодировку и бюджет байт, а для встроенной managed-строки с MarshalAs используйте ReadManaged<T>. RemoteMemoryObject удобен как обёртка адреса, но не обнаруживает layout и не превращает меняющиеся данные в атомарный снимок.

Собранные значения вместе с PID/поколением подключения и временем чтения передайте в Blazor как один снимок. UI рисует его без новых обращений к процессу; при неудачном обновлении показывает ошибку/устаревание. Обход живой памяти не гарантирует согласованность между первым и последним чтением. Владелец удерживает reader живым до конца обхода и останавливает обновление перед освобождением. Контракт Read<T>(address, size) сверён с EyeAuras 20fd3d4; реальные адреса и поля Assault Cube остаются данными конкретного примера.

Общая схема

  • Открыть целевой процесс и создать память с привязкой к модулю.
  • Описать корневой объект игры, локального игрока, список сущностей и сами сущности как классы-обёртки над памятью.
  • Считать количество сущностей и указатель на список сущностей из известных offsets модуля.
  • Пройтись по указателям сущностей и прочитать простые поля вроде имени, позиции, здоровья, брони, команды или типа.
  • Показать текущий снимок данных в небольшом окне Blazor, таблице, радаре или логе.

Что нужно решить заранее

  • Какой backend процесса использовать: локальный процесс, MPFS/LC, KD или свой backend.
  • Представлять сущности как живые объекты памяти или как неизменяемые снимки.
  • Как часто обновлять список.
  • Что делать с невалидными или null-указателями: пропускать, показывать как ошибки или останавливать обновление.
  • Каким будет UI: таблица, радар, карта или отладочный лог.

Что посмотреть в API

  • IProcess
  • LocalProcess
  • LCProcess
  • KDProcess
  • IMemory
  • MemoryOfModule
  • RemoteMemoryObject
  • Read<T>
  • ReadString
  • IDialogWindowUnstableScriptingApi
  • BlazorReactiveComponent
  • BlazorReactiveComponent<T>

Чего лучше избегать

  • Считать offsets стабильными между разными версиями игры.
  • Читать все поля на каждом кадре, если на экране показывается только часть данных.
  • Переносить математику указателей в UI-код.
  • Падать на null, устаревших или невалидных указателях сущностей.
  • Слишком рано превращать простой reader списка сущностей в полноценный bot framework.

Связанные материалы

  • memory/processes.md
  • windows-subsystems/blazor-windows.md
  • reverse-engineering/reprocess.md
  • scripting/runtime.md