CLEO Redux SDK
SDK позволяет создавать новые скриптовые команды для любой игры, которую поддерживает CLEO Redux. Он не зависит от названия игры и базовой среды выполнения (CS или JS). На данный момент CLEO предоставляет SDK для языков C++ и Rust.
Поддержка платформ
CLEO Redux предоставляет SDK как для 32-битных, так и для 64-битных игр. Между ними есть одно заметное отличие: на 32-битной платформе функции SDK GetIntParam
и SetIntParam
работают с 32-битными числами со знаком, тогда как на 64-битной платформе они работают с 64-битными числами со знаком (объявлено как тип isize
).
Структура плагина
Каждый плагин представляет собой динамическую библиотеку с расширением .cleo
, которую необходимо поместить в CLEO\CLEO_PLUGINS
. CLEO Redux сканирует этот каталог при запуске и загружает все файлы .cleo
, используя функцию WinAPI LoadLibrary
. Чтобы зарегистрировать обработчик для новой команды, плагин должен вызвать RegisterCommand
в функции DllMain. Как только пользовательский скрипт встречает эту команду, CLEO Redux вызывает обработчик с одним аргументом, который является указателем на текущий контекст. Этот указатель необходимо использовать для вызова других методов SDK.
Соглашение об именовании
Для 64-битных плагинов рекомендуется использовать 64
в именах (например, myplugin64.cleo
).
Небезопасные команды
Команды, использующие низкоуровневый WinAPI и потенциально способные нанести вред среде пользователя, должны быть явно зарегистрированы с помощью токена разрешения (третий аргумент RegisterCommand
). Пользователь может запретить использование небезопасных команд в скриптах с помощью настройки разрешений. На данный момент используются три токена разрешений: mem
, fs
и dll
. Ими отмечаются команды, работающие с хост-процессом, пользовательскими файлами и внешними библиотеками.
Командный интерфейс
CLEO Redux использует Sanny Builder Library, чтобы узнать интерфейс любой команды. Чтобы новая команда стала доступной в сценариях, файл JSON (gta3.json
, vc.json
, sa.json
) должен иметь определение команды, включая имя, совпадающее со значением, которое плагин использует RegisterCommand
с. Например. если подключаемый модуль регистрирует команду SHOW_MESSAGE
, в файле JSON должна быть команда со свойством имени, установленным на SHOW_MESSAGE
. Количество и порядок входных и выходных параметров в определении должны соответствовать порядку методов, используемых подключаемым модулем (т. е. GetXXXParam
для каждого входного аргумента и SetXXXParam
для каждого выходного аргумента).
Запрос кодов операций
Коды операций назначаются новым командам в Sanny Builder Library в зависимости от их доступности, сходства с существующими командами в других играх и других факторов. Чтобы запросить код операции, обратитесь к сопровождающим Sanny Builder Library на GitHub https://github.com/sannybuilder/library/issues.
Зачем использовать имена команд, а не идентификатор для поиска команды?
Одной из распространенных проблем с плагинами CLEO Library было то, что команды, созданные разными людьми, часто имели конфликты идентификаторов. Если два плагина добавляют команды с одинаковым идентификатором, использовать их оба невозможно. Использование строковых имен сводит к минимуму коллизии с пользовательскими плагинами, а также с собственными кодами операций. Определения библиотеки гарантируют, что каждая команда требует только доступный идентификатор. Также это помогает отслеживать и документировать плагины в одном месте.
Версия SDK
Текущая версия 1
. Изменения в SDK увеличат это число на единицу.
Соглашение о разрешении пути
Строковые аргументы, представляющие путь к каталогу или файлу, должны быть нормализованы с помощью функции SDK ResolvePath
. Эта функция принимает путь и возвращает абсолютный путь, разрешенный по следующим правилам:
- абсолютный путь разрешается как есть
- путь, начинающийся с "CLEO/" или "CLEO\", разрешается относительно каталога CLEO, который либо
- {игра}\CLEO или
- {пользователь}\AppData\Roaming\CLEO Redux\CLEO
- все остальные пути разрешаются относительно текущего рабочего каталога (каталог игры)
Строковые аргументы
Строки, передаваемые в методы SDK имеют кодировку UTF-8.
Если сценарий использует целочисленное значение вместо ожидаемой строки, SDK обрабатывает это число как указатель на последовательность символов UTF-8, заканчивающуюся нулем, для чтения или на достаточно большой буфер для сохранения результата:
IniFile.WriteString(0xDEADBEEF, "my.ini", "section", "key")
SDK прочитает строку с адреса 0xDEADBEEF
и запишет ее в ini-файл.
0AF4: read_string_from_ini_file 'my.ini' section 'section' key 'key' store_to 0xDEADBEEF
SDK прочитает строку из ini-файла и запишет ее по адресу 0xDEADBEEF
.
C++ SDK
Пользовательские плагины могут вызывать методы, предоставляемые CLEO Redux, используя предоставленный файл .lib
. Включите cleo_redux_sdk.h
в свой проект DLL и свяжите двоичный файл с cleo_redux.lib
(или cleo_redux64.lib
, если целевая платформа x86_64), и вы сможете начать писать новые команды.
Пример
См. подключаемый модуль IniFiles
, который включает проект для Visual Studio 2019. Он добавляет статический класс IniFile
со следующими методами:
interface IniFile {
ReadFloat(path: string, section: string, key: string): float | undefined;
ReadInt(path: string, section: string, key: string): int | undefined;
ReadString(path: string, section: string, key: string): string | undefined;
WriteFloat(value: float, path: string, section: string, key: string): boolean;
WriteInt(value: int, path: string, section: string, key: string): boolean;
WriteString(value: string, path: string, section: string, key: string): boolean;
}
Дополнительную информацию см. в библиотеке Sanny Builder: https://library.sannybuilder.com/#/sa_unreal/classes/IniFile. Для использования класса IniFile
требуется fs
разрешение.
Rust SDK
Rust SDK использует интерфейс, аналогичный интерфейсу C++, с некоторыми дополнительными методами переноса, позволяющими легко конвертировать типы C и Rust. Заголовочный файл доступен в виде crate на crates.io. См. документацию здесь.
Пример
См. плагин Dylib
. Он добавляет класс DynamicLibrary
со следующими методами:
declare class DynamicLibrary {
constructor(handle: number);
static Load(libraryFileName: string): DynamicLibrary | undefined;
free(): void;
getProcedure(procName: string): int | undefined;
}
Дополнительную информацию см. в Sanny Builder Library: https://library.sannybuilder.com/#/sa_unreal/classes/DynamicLibrary. Для использования класса DynamicLibrary
требуется dll
разрешение.