Repository navigation
RU UO Topic scripts runtime
Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
Главная · C# · IDE · UO API · A–Z · Примеры · Языки
Запуск, пауза, остановка скриптов и процедур, сведения об экземплярах, события и ожидание. Terminate и StopScript работают на разных уровнях выполнения.
| Тема | Команды и пояснения |
|---|---|
| StartScript | UO.StartScript |
| StopScript | UO.StopScript |
| StopAllScripts | UO.StopAllScripts |
| PauseResumeScript | UO.PauseResumeScript |
| Script State | UO.GetScriptState |
| Script List | UO.GetScriptsList · UO.GetScriptsCount |
| Script Name | UO.GetScriptName · UO.SetScriptName |
| Script Path | UO.GetScriptPath |
| CallSub | UO.CallSub |
| SubExists | UO.SubExists |
| Events | UO.SetEvent · UO.SetEventProc |
| Timers | UO.Timer · UO.Wait |
| Disconnect Behaviour | UO.GetPauseScriptOnDisconnectStatus · UO.SetPauseScriptOnDisconnectStatus |
UO.StartScript · UO.StopScript · UO.StopAllScripts · UO.PauseResumeScript · UO.GetScriptName · UO.SetScriptName · UO.GetScriptPath · UO.GetScriptsCount · UO.GetScriptsList · UO.GetScriptState · UO.Exec · UO.Launch
UO.CallSub · UO.SubExists · UO.FunRunning · UO.Terminate · UO.TerminateAll · UO.SetEvent · UO.SetEventProc
UO.Wait · UO.Waiting · UO.Timer · UO.Time · UO.Date
UO.GetPauseScriptOnDisconnectStatus · UO.SetPauseScriptOnDisconnectStatus
В каждой карточке команды есть несколько самостоятельных сценариев: прямой код, функции и классы. Ниже приведены отдельные короткие сценарии; ограничения и полный разбор находятся в карточках.
Параметры, результат и все сценарии
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
UO.Print(Convert.ToString(index) + ": " + UO.GetScriptName(index));
}Параметры, результат и все сценарии
for (int cycle = (int)(1); cycle <= 10; cycle += (int)(1))
{
if (Truth(UO.Dead()))
{
UO.Print("Character is dead: stopping all C# scripts");
UO.TerminateAll();
}
await Delay(250);
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.CallSub(object? subrutineName);Запускает C#-делегат, заранее зарегистрированный в текущем выполнении через RegisterRoutine(name, handler). Вызов возвращает управление до завершения помощника; одну зарегистрированную задачу нельзя накладывать саму на себя.
-
subrutineName— строковое имя, заданное RegisterRoutine. Пробелы по краям удаляются; поиск зарегистрированного имени не зависит от регистра.
void — результата нет; неизвестное имя CallSub вызывает ошибку, а повторный запуск уже активного имени пропускается.
Значение UO.FunRunning(name) == 0 возможно также сразу после запроса отмены. Оно не означает, что блок finally предыдущего callback уже завершился. Повторный CallSub или Exec того же локального имени пропускается, пока прежний обработчик фактически не завершит работу.
- Регистрация и задачи принадлежат одному выполнению. Другой персонаж, профиль или последующий запуск имеет собственный реестр.
- RegisterRoutine принимает
Action,Func<Task>либо делегат с массивом строковых аргументов для Exec. Удаление регистрации не запускает код и исключает дальнейший поиск имени. - Основной скрипт должен оставаться активным, пока нужны его помощники: после его окончания задачи отменяются, а регистрации и подписки освобождаются.
- FunRunning не является индексом менеджера. GetScriptsList и GetScriptState описывают самостоятельные запуски файлов; локальный callback отдельного индекса не получает.
- Ошибка callback передаётся основному скрипту на следующей проверке. WaitAsync, UO.Wait и инструментированные C#-циклы поддерживают паузу, отмену и обработку очереди событий.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("Hello", () => UO.Print("Hello from a routine"));
UO.CallSub("Hello");
while (UO.FunRunning("Hello") != 0) await WaitAsync(25);Параметры и ход выполнения:
- WeightWatch — имя процедуры ниже. Main возвращает 77, не ожидая трёх замеров; 77 — результат Main, не CallSub.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
UO.CallSub("WeightWatch");
while (UO.FunRunning("WeightWatch") != 0) await WaitAsync(25);
return 77;
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- StartIfIdle сначала проверяет определение, затем активность. false означает, что запрос не отправлен. true означает только отправленный запрос CallSub, а не подтверждение запуска или завершения.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
var launched = StartIfIdle("WeightWatch");
while (UO.FunRunning("WeightWatch") != 0)
await WaitAsync(25);
return launched;
return null;
}
dynamic StartIfIdle(dynamic name)
{
if (!(Truth(UO.SubExists(name))))
{
return false;
}
if (Truth(UO.FunRunning(name)))
{
return false;
}
UO.CallSub(name);
return true;
}
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Первый CallSub запускает WeightWatch, второй — ManaWatch. Запуски независимы и не обмениваются локальными переменными; порядок их вывода не гарантирован.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
var registrationManaWatch = RegisterRoutine("ManaWatch", ManaWatch);
UO.CallSub("WeightWatch");
UO.CallSub("ManaWatch");
while (UO.FunRunning("WeightWatch") != 0 || UO.FunRunning("ManaWatch") != 0)
await WaitAsync(25);
return null;
}
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
void ManaWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Mana: " + Convert.ToString(UO.Mana()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: subrutineName (String)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.CallSub. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.Exec:bridge.Exec(subrutineName).
Внутренний код реализации, не самостоятельный скрипт.
case "CallSub":
string called = Convert.ToString(arguments[0]) ?? "";
if (Exists(called)) Start(called);
else if (events is ICSharpScriptHost host && host.HasCSharpScript(called)) host.ExecuteCSharpScript("exec \"" + called + "\"");
else throw new ArgumentException($"Register the C# routine or load a C# script entry named '{called}' before calling it.");
return true;Внутренний код реализации, не самостоятельный скрипт.
public void CallSub(string subrutineName) => bridge.Exec(subrutineName);Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Date();Читает местную календарную дату компьютера числом YYMMDD. Удобна для названия дневной серии действий или обнаружения смены даты.
Параметров нет.
int YYMMDD: 2026-09-30 -> 260930. Разделителей и сохраняемых начальных нулей нет. Это не длительность, не Unix-время и не true/false.
- Параметров нет, форм с аргументами нет. Пустые скобки только читают время: вызов не ждёт, не запускает таймер и не отправляет пакеты в игру.
- RealTimeSource.Now читает DateTime.Now: местную дату/время компьютера, не UTC, не время шарда и не игровые часы. Часовой пояс, летнее время и ручной перевод часов влияют на результат. Каждый вызов фиксирует отдельный момент.
- Сохраняются только две последние цифры года: и 2000-01-01, и 2100-01-01 дают 101. Разные столетия не различаются. Отдельные вызовы Date и Time могут попасть по разные стороны полуночи.
- Не вычитайте календарные коды для расчёта задержки. Используйте Timer() и две отметки одного запуска. Календарные часы могут перевестись назад.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Date();
UO.Print("Date: " + Convert.ToString(result));Параметры и ход выполнения:
- Результат вызова без параметров сохраняется один раз. sessionLabel — строка вроде harvest-260930. Print только показывает название: файл не создаётся, сбор ресурсов не запускается.
var dateStamp = UO.Date();
var sessionLabel = "harvest-" + Convert.ToString(dateStamp);
UO.Print(sessionLabel);Параметры и ход выполнения:
- originalDate хранит исходную дату. Timer ограничивает наблюдение 60 секундами, UO.Wait(1000) даёт проверку примерно раз в секунду. Смена даты завершает Main. Пример не ждёт полуночи бесконечно и не утверждает, что сменился день на сервере.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var originalDate = UO.Date();
var started = Environment.TickCount;
while (Truth(Environment.TickCount - started < 60.0))
{
if (Truth(UO.Date() != originalDate))
{
UO.Print("Local date changed; end this batch");
return null;
}
await Delay(1000);
}
UO.Print("No date change observed within one minute");
return null;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- MonthPart(stamp) показана целиком: деление с округлением вниз и MOD 100 извлекают месяц. day — две последние цифры; shortYear — неполный год. Для 260930 получаются 26, 9, 30.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var stamp = UO.Date();
var month = MonthPart(stamp);
var day = stamp % 100;
var shortYear = stamp / 10000;
UO.Print(Convert.ToString(shortYear) + "/" + Convert.ToString(month) + "/" + Convert.ToString(day));
return null;
}
dynamic MonthPart(dynamic stamp)
{
return stamp / 100 % 100;
}
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: int / Integer.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public int Date()
{
var now = timeSource.Now;
return (now.Year % 100) * 10000 + now.Month * 100 + now.Day;
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.Exec(object? parameters);Выполняет текстовую игровую команду либо запускает зарегистрированный C#-делегат или загруженный C#-файл.
-
parameters— строка команды: например "useskill Hiding", "exec Worker 42" или "exec Child.csx::Main 'north gate' 42". Выражение C# вроде 2+3 внутри строки автоматически не вычисляется.
void: результата нет. Возврат управления не означает окончания запуска или подтверждения игрового действия сервером.
Значение UO.FunRunning(name) == 0 возможно также сразу после запроса отмены. Оно не означает, что блок finally предыдущего callback уже завершился. Повторный CallSub или Exec того же локального имени пропускается, пока прежний обработчик фактически не завершит работу.
- Сначала проверяется локальный реестр RegisterRoutine. Поддерживаются "Name args", "exec Name args" и "_exec Name args". Делегат получает string[]: аргумент 42 остаётся строкой "42", а '00123' сохраняет ведущие нули. Одинарные либо двойные кавычки объединяют аргумент с пробелами; '' задаёт пустую строку. Незакрытая кавычка вызывает ошибку. В этом маршруте обратный слеш сохраняется буквально; не используйте синтаксис экранирования C# внутри уже готового текста команды.
- Локальный делегат запускается асинхронно. Для ожидания его окончания используйте FunRunning и WaitAsync. Повторный запуск активного имени не создаёт копию и не снимает паузу. Ошибка помощника передаётся основному скрипту на контрольной точке.
- Явно загруженные файловые входы запускаются текущим менеджером с собственным Args и временем жизни. Само принятие запроса запуска ещё не означает, что файл закончил работу.
- Обычные игровые команды передаются native-диспетчеру. Там сохраняются контракты параметров соответствующей UO-команды; Print/Msg/Say/ConsolePrint/TextPrint объединяют остаток строки в текст. Для точных C#-типов и выражений используйте прямой вызов вроде UO.UseSkill("Hiding"). Неизвестная команда, неподходящие аргументы или кавычки могут вызвать исключение, перехватываемое try/catch.
- Консольные алиасы: sayu → Say, closeuo → CloseHandle, CountOnGround → CountGround, clearignorelist → IgnoreReset, canceltarget → CancelTarget, cancelmove → MoveOff.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("Hello", () => UO.Print("Hello from a routine"));
UO.Exec("exec Hello");
while (UO.FunRunning("Hello") != 0) await WaitAsync(25);Параметры и ход выполнения:
- Hiding — единственный аргумент UseSkill. При входе в мир клиент отправляет запрос использования навыка; успех скрытия определяет сервер. Та же операция прямым вызовом: UO.UseSkill("Hiding").
UO.Exec("useskill Hiding");Параметры и ход выполнения:
- SelectSavedRoute определена ниже и записывает название выбранного маршрута. Кавычки вокруг 00123 сохраняют ведущие нули. Exec запускает зарегистрированный делегат асинхронно. Цикл с FunRunning и WaitAsync явно ожидает его окончания, затем сценарий возвращает строку 00123. Это учебное сохранение имени, а не команда движения.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var registration = RegisterRoutine("SelectSavedRoute", (Action<string[]>)(arguments =>
{
if (arguments.Length == 1)
SelectSavedRoute(arguments[0]);
}));
UO.Exec("SelectSavedRoute '00123'");
while (UO.FunRunning("SelectSavedRoute") != 0)
await WaitAsync(25);
return UO.GetGlobal("manual", "savedRoute");
return null;
}
void SelectSavedRoute(dynamic name)
{
UO.SetGlobal("manual", "savedRoute", name);
}Параметры и ход выполнения:
- Запускайте этот C#-скрипт: RegisterRoutine связывает имя WeightWatch с объявленной функцией текущего выполнения. exec WeightWatch запускает три замера веса с интервалом 1000 мс и не ждёт их завершения. Основной скрипт остаётся активным, пока работает локальный помощник; у помощника нет отдельного индекса менеджера. Если задача уже на паузе, повторный Exec её не возобновляет.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
UO.Exec("exec WeightWatch");
while (UO.FunRunning("WeightWatch") != 0)
await WaitAsync(25);
return null;
}
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}Параметры и ход выполнения:
- Замените путь существующим C#-файлом со своей процедурой Main. startscript загружает файл и запрашивает запуск Main. Кавычки принадлежат текстовой команде; обратные слеши пути сохраняются. Ошибки запуска смотрите в IDE, так как Exec не возвращает подтверждения.
UO.Exec("startscript 'C:\\UO Scripts\\Gather.csx'");C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: parameters (String)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionRuntime.Exec. -
InjectionScript.Runtime.InjectionRuntime.Tokenize:Tokenize(parameters). -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.Exec:bridge.Exec(parts[1].Text). -
InjectionScript.Runtime.InjectionRuntime.TryHandleLegacyConsoleCommand:TryHandleLegacyConsoleCommand(command, rawArguments). -
InjectionScript.Runtime.InjectionRuntime.NormalizeConsoleAlias:NormalizeConsoleAlias(command). -
InjectionScript.Runtime.InjectionRuntime.IsRemainderTextCommand:IsRemainderTextCommand(command). -
InjectionScript.Runtime.InjectionRuntime.ToConsoleValue:ToConsoleValue(token.Text). -
InjectionScript.Runtime.InjectionRuntime.CallNativeSubrutine:CallNativeSubrutine(command, args).
Внутренний код реализации, не самостоятельный скрипт.
case "Exec":
var words = CommandWords(Convert.ToString(arguments[0]) ?? "");
if (words.Length == 0) return false;
int offset = words[0].Equals("exec", StringComparison.OrdinalIgnoreCase) || words[0].Equals("_exec", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
if (words.Length > offset && Exists(words[offset]))
{ Start(words[offset], words.Skip(offset + 1).ToArray()); return true; }
if (words.Length > offset && events is ICSharpScriptHost scriptHost
&& (offset == 1 || scriptHost.HasCSharpScript(words[offset])))
{
string command = Convert.ToString(arguments[0]) ?? "";
if (words[0].Equals("_exec", StringComparison.OrdinalIgnoreCase)) command = "exec" + command.TrimStart()[5..];
scriptHost.ExecuteCSharpScript(command); return true;
}
return false;Внутренний код реализации, не самостоятельный скрипт.
public void Exec(string parameters)
{
ConsoleToken[] parts = Tokenize(parameters).ToArray();
if (parts.Length == 0)
return;
string command = parts[0].Text;
if (command.Equals("exec", StringComparison.OrdinalIgnoreCase))
{
if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[1].Text))
throw new NativeSubrutineException("Usage: exec script_function");
bridge.Exec(parts[1].Text);
return;
}
ConsoleToken[] arguments = parts.Skip(1).ToArray();
string[] rawArguments = arguments.Select(token => token.Text).ToArray();
if (TryHandleLegacyConsoleCommand(command, rawArguments))
return;
command = NormalizeConsoleAlias(command);
if (IsRemainderTextCommand(command) && rawArguments.Length > 0)
arguments = new[] { new ConsoleToken(string.Join(" ", rawArguments), true) };
else if (command.Equals("ColorPrint", StringComparison.OrdinalIgnoreCase) && rawArguments.Length > 1)
arguments = new[] { arguments[0], new ConsoleToken(string.Join(" ", rawArguments.Skip(1)), true) };
else if (command.Equals("CharPrint", StringComparison.OrdinalIgnoreCase) && rawArguments.Length > 2)
arguments = new[] { arguments[0], arguments[1], new ConsoleToken(string.Join(" ", rawArguments.Skip(2)), true) };
InjectionValue[] args = arguments.Select(token => token.Quoted
? new InjectionValue(token.Text) : ToConsoleValue(token.Text)).ToArray();
CallNativeSubrutine(command, args);
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.FunRunning(object? subrutineName);Проверяет, выполняется ли зарегистрированный C#-callback с указанным именем. Результат 1 включает ручную паузу; завершённая либо отменяющаяся задача даёт 0.
-
subrutineName— строковое имя, заданное RegisterRoutine. Пробелы по краям удаляются; поиск зарегистрированного имени не зависит от регистра.
int: 1 — условие выполнено, 0 — не выполнено. Сохраните результат одного вызова, если он нужен нескольким проверкам.
Значение UO.FunRunning(name) == 0 возможно также сразу после запроса отмены. Оно не означает, что блок finally предыдущего callback уже завершился. Повторный CallSub или Exec того же локального имени пропускается, пока прежний обработчик фактически не завершит работу.
- Регистрация и задачи принадлежат одному выполнению. Другой персонаж, профиль или последующий запуск имеет собственный реестр.
- RegisterRoutine принимает
Action,Func<Task>либо делегат с массивом строковых аргументов для Exec. Удаление регистрации не запускает код и исключает дальнейший поиск имени. - Основной скрипт должен оставаться активным, пока нужны его помощники: после его окончания задачи отменяются, а регистрации и подписки освобождаются.
- FunRunning не является индексом менеджера. GetScriptsList и GetScriptState описывают самостоятельные запуски файлов; локальный callback отдельного индекса не получает.
- Ошибка callback передаётся основному скрипту на следующей проверке. WaitAsync, UO.Wait и инструментированные C#-циклы поддерживают паузу, отмену и обработку очереди событий.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("Hello", async () => await WaitAsync(100));
UO.CallSub("Hello");
UO.Print("Running flag: " + UO.FunRunning("Hello"));
while (UO.FunRunning("Hello") != 0) await WaitAsync(25);Параметры и ход выполнения:
- Сначала RegisterRoutine связывает имя с C#-функцией. FunRunning проверяет задачу этого выполнения, включая паузу. Основной скрипт остаётся активным до завершения помощника.
var registration = RegisterRoutine("WeightWatch", WatchWeight);
if (UO.FunRunning("WeightWatch") == 0) UO.CallSub("WeightWatch");
while (UO.FunRunning("WeightWatch") != 0) await WaitAsync(25);
async Task WatchWeight()
{
for (int sample = 0; sample < 3; sample++)
{
UO.Print($"Weight: {UO.Weight()}");
await WaitAsync(250);
}
}Параметры и ход выполнения:
- Async-делегат меняет общий счётчик через
Interlocked. После FunRunning=0 результат читается черезVolatile. Это локальный callback; отдельного индекса GetScriptsList у него нет.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
int completed = 0;
var registration = RegisterRoutine("Worker", async () =>
{
await WaitAsync(150);
Interlocked.Exchange(ref completed, 1);
});
UO.CallSub("Worker");
UO.Print($"Worker active: {UO.FunRunning("Worker") != 0}");
while (UO.FunRunning("Worker") != 0)
await WaitAsync(25);
return Volatile.Read(ref completed) == 1;
return null;
}Параметры и ход выполнения:
- Terminate выбирает зарегистрированную задачу текущего выполнения. Ожидание WaitAsync использует её токен отмены.
finallyвыполняет очистку; дальнейшие игровые действия отменённой задачи не допускаются.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
int cleanupDone = 0;
var registration = RegisterRoutine("Worker", async () =>
{
try
{
await WaitAsync(5000);
}
finally
{
Interlocked.Exchange(ref cleanupDone, 1);
}
});
UO.CallSub("Worker");
await WaitAsync(100);
if (UO.FunRunning("Worker") != 0)
UO.Terminate("Worker");
while (UO.FunRunning("Worker") != 0)
await WaitAsync(25);
while (Volatile.Read(ref cleanupDone) == 0)
await WaitAsync(25);
return true;
return null;
}
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: subrutineName (String)
Результат: int / Integer.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.FunRunning. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.FunRunning:bridge.FunRunning(subrutineName).
Внутренний код реализации, не самостоятельный скрипт.
case "FunRunning":
string runningName = Convert.ToString(arguments[0]) ?? "";
result = IsRunning(runningName) || events is ICSharpScriptHost runningHost && runningHost.IsCSharpScriptRunning(runningName) ? 1 : 0;
return true;Внутренний код реализации, не самостоятельный скрипт.
public int FunRunning(string subrutineName) => bridge.FunRunning(subrutineName) ? 1 : 0;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
dynamic UO.GetPauseScriptOnDisconnectStatus();Читает настройку паузы скриптов при отключении менеджера.
Параметров нет.
int 1 — PauseScriptsOnDisconnect включён; 0 — выключен.
- Читает флаг менеджера, не текущую паузу отдельного скрипта. Сам вызов не ставит и не снимает паузу.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
object? result = UO.GetPauseScriptOnDisconnectStatus();
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));Параметры и ход выполнения:
- Значение описывает настройку менеджера.
var enabled = UO.GetPauseScriptOnDisconnectStatus();
UO.Print(Convert.ToString(enabled));Параметры и ход выполнения:
- Флаг настройки и соединение читаются независимо.
return RunScenario();
object? RunScenario()
{
var pauseOnDisconnect = UO.GetPauseScriptOnDisconnectStatus();
var online = UO.Connected();
UO.Print(Convert.ToString(pauseOnDisconnect) + " " + Convert.ToString(online));
return null;
}Параметры и ход выполнения:
- Переменная содержит снимок настройки на момент чтения.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
var saved = UO.GetPauseScriptOnDisconnectStatus();
await Delay(100);
UO.Print(Convert.ToString(saved));
return null;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: dynamic / Any.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetPauseScriptOnDisconnectStatus:bridge.GetPauseScriptOnDisconnectStatus().
Внутренний код реализации, не самостоятельный скрипт.
case "getpausescriptondisconnectstatus": return new InjectionValue(bridge.GetPauseScriptOnDisconnectStatus());Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
string UO.GetScriptName(object? scriptIndex);Читает отображаемое имя активного запуска.
-
scriptIndex— Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
string: отображаемое имя либо "", если индекса нет. У существующего запуска имя тоже может быть явно установлено в пустую строку.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
- ScriptIndex=0 — первый текущий запуск, не обязательно вызывающий скрипт. SetScriptName меняет отображаемое имя, не переименовывая файл.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetScriptName(0);
UO.Print("GetScriptName: " + Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- ScriptIndex=0 — первый текущий запуск, не обязательно вызывающий скрипт. SetScriptName меняет отображаемое имя, не переименовывая файл.
- string: отображаемое имя либо "", если индекса нет. У существующего запуска имя тоже может быть явно установлено в пустую строку.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
var index = 0;
var name = UO.GetScriptName(index);
UO.Print(name);Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- ScriptIndex=0 — первый текущий запуск, не обязательно вызывающий скрипт. SetScriptName меняет отображаемое имя, не переименовывая файл.
- string: отображаемое имя либо "", если индекса нет. У существующего запуска имя тоже может быть явно установлено в пустую строку.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return RunScenario();
object? RunScenario()
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
var name = UO.GetScriptName(index);
UO.Print(Convert.ToString(index) + " = " + name);
}
return null;
}Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- DescribeScript проверяет состояние и объединяет имя с путём. Между вызовами возможна остановка; "missing" — значение нашей функции, а не результат GetScriptName.
- string: отображаемое имя либо "", если индекса нет. У существующего запуска имя тоже может быть явно установлено в пустую строку.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
UO.Print(DescribeScript(0));
return null;
}
dynamic DescribeScript(dynamic index)
{
if (Truth(UO.GetScriptState(index) == 0))
{
return "missing";
}
return UO.GetScriptName(index) + " | " + UO.GetScriptPath(index);
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any)
Результат: string / String.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetScriptName:bridge.GetScriptName(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "getscriptname": return new InjectionValue(bridge.GetScriptName(Arg(0)));Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
string UO.GetScriptPath(object? scriptIndex);Читает путь исходного файла активного запуска.
-
scriptIndex— Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
string: сохранённый путь исходного файла либо "", если индекса нет. При запуске файла это обычно полный путь; у команды или исходника в памяти обычного файла может не быть.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
- ScriptIndex=0 выбирает первый текущий запуск. Результат указывает его исходник; команда не открывает, не сохраняет и не запускает этот файл.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetScriptPath(0);
UO.Print("GetScriptPath: " + Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- ScriptIndex=0 выбирает первый текущий запуск. Результат указывает его исходник; команда не открывает, не сохраняет и не запускает этот файл.
- string: сохранённый путь исходного файла либо "", если индекса нет. При запуске файла это обычно полный путь; у команды или исходника в памяти обычного файла может не быть.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
var index = 0;
var path = UO.GetScriptPath(index);
if (Truth(path!=""))
{
UO.Print(path);
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- ScriptIndex=0 выбирает первый текущий запуск. Результат указывает его исходник; команда не открывает, не сохраняет и не запускает этот файл.
- string: сохранённый путь исходного файла либо "", если индекса нет. При запуске файла это обычно полный путь; у команды или исходника в памяти обычного файла может не быть.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return RunScenario();
object? RunScenario()
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
UO.Print(UO.GetScriptName(index) + " -> " + UO.GetScriptPath(index));
}
return null;
}Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- ReadScriptPath подставляет параметр fallback только при пустом пути. Это отдельная функция, а не новая перегрузка GetScriptPath.
- string: сохранённый путь исходного файла либо "", если индекса нет. При запуске файла это обычно полный путь; у команды или исходника в памяти обычного файла может не быть.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
UO.Print(ReadScriptPath(0, "path unavailable"));
return null;
}
dynamic ReadScriptPath(dynamic index, dynamic fallback)
{
var path = UO.GetScriptPath(index);
if (Truth(path == ""))
{
return fallback;
}
return path;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any)
Результат: string / String.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetScriptPath:bridge.GetScriptPath(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "getscriptpath": return new InjectionValue(bridge.GetScriptPath(Arg(0)));Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.GetScriptState(object? scriptIndex);Читает состояние выполнения по индексу.
-
scriptIndex— Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
int — код состояния: 0 = нет/неизвестно, 1 = выполняется, 2 = пауза. Это не bool: явно сравнивайте с 1 или 2.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
- Учитывается ручная/отладочная пауза и настроенная пауза при отключении. Состояние 1 не гарантирует, что скрипт прямо сейчас расходует процессор или получает данные сервера.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetScriptState(0);
UO.Print("GetScriptState: " + Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- Учитывается ручная/отладочная пауза и настроенная пауза при отключении. Состояние 1 не гарантирует, что скрипт прямо сейчас расходует процессор или получает данные сервера.
- int — код состояния: 0 = нет/неизвестно, 1 = выполняется, 2 = пауза. Это не bool: явно сравнивайте с 1 или 2.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
int state = UO.GetScriptState(0);
string text = state switch
{
1 => "running",
2 => "paused",
_ => "unknown"
};
UO.Print(text);Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- Учитывается ручная/отладочная пауза и настроенная пауза при отключении. Состояние 1 не гарантирует, что скрипт прямо сейчас расходует процессор или получает данные сервера.
- int — код состояния: 0 = нет/неизвестно, 1 = выполняется, 2 = пауза. Это не bool: явно сравнивайте с 1 или 2.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return RunScenario();
object? RunScenario()
{
var paused = 0;
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptState(index) == 2))
{
paused += 1;
}
}
UO.Print(Convert.ToString(paused));
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- IsScriptActive преобразует 1 и 2 в true, а 0 в false. Сама GetScriptState по-прежнему возвращает числовой код состояния.
- int — код состояния: 0 = нет/неизвестно, 1 = выполняется, 2 = пауза. Это не bool: явно сравнивайте с 1 или 2.
- Обязательный ScriptIndex — целое число, индекс с нуля из свежего GetScriptsList. Для отрицательного или отсутствующего индекса возвращается описанный пустой/неизвестный результат. Не передавайте serial предмета, имя процедуры или ID запуска из IDE.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
if (Truth(Truth(IsScriptActive(0)) == true))
{
UO.Print("running or paused");
}
else
{
UO.Print("not active");
}
return null;
}
dynamic IsScriptActive(dynamic index)
{
var state = UO.GetScriptState(index);
return Truth(state == 1) || Truth(state == 2);
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetScriptState:bridge.GetScriptState(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "getscriptstate": return new InjectionValue(bridge.GetScriptState(Arg(0)));Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.GetScriptsCount();Считает активные запуски в этом клиенте.
Параметров нет.
int >= 0: число активных запусков, включая приостановленные. Это количество, а не bool и не индекс скрипта.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
- Аргументов нет. Подсчёт не сортирует список и не меняет состояние запусков.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.GetScriptsCount();
UO.Print("GetScriptsCount: " + Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- Аргументов нет. Подсчёт не сортирует список и не меняет состояние запусков.
- int >= 0: число активных запусков, включая приостановленные. Это количество, а не bool и не индекс скрипта.
var count = UO.GetScriptsCount();
UO.Print(Convert.ToString(count));Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- Аргументов нет. Подсчёт не сортирует список и не меняет состояние запусков.
- int >= 0: число активных запусков, включая приостановленные. Это количество, а не bool и не индекс скрипта.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var before = UO.GetScriptsCount();
await Delay(250);
var after = UO.GetScriptsCount();
UO.Print(Convert.ToString(after - before));
return null;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- HasOtherScripts сравнивает количество с 1: вызывающий скрипт обычно занимает одну запись. В отличие от GetScriptsCount, вспомогательная функция возвращает true/false.
- int >= 0: число активных запусков, включая приостановленные. Это количество, а не bool и не индекс скрипта.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
if (Truth(HasOtherScripts()))
{
UO.Print("Other executions are active");
}
else
{
UO.Print("No other active executions");
}
return null;
}
dynamic HasOtherScripts()
{
var count = UO.GetScriptsCount();
return count > 1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetScriptsCount:bridge.GetScriptsCount().
Внутренний код реализации, не самостоятельный скрипт.
case "getscriptscount": return new InjectionValue(bridge.GetScriptsCount());Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
dynamic UO.GetScriptsList();Возвращает текущие числовые индексы скриптов.
Параметров нет.
Array из int: индексы 0..N-1 либо пустой массив. Элементы — числа, а не имена и не текстовые записи.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
- Аргументов нет. Каждое число передавайте в соответствующий getter имени, пути или состояния. Полученный массив — отдельный снимок; его изменение не управляет скриптами.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
object? result = UO.GetScriptsList();
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- Аргументов нет. Каждое число передавайте в соответствующий getter имени, пути или состояния. Полученный массив — отдельный снимок; его изменение не управляет скриптами.
- Array из int: индексы 0..N-1 либо пустой массив. Элементы — числа, а не имена и не текстовые записи.
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
UO.Print(Convert.ToString(index) + ": " + UO.GetScriptName(index));
}Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- Аргументов нет. Каждое число передавайте в соответствующий getter имени, пути или состояния. Полученный массив — отдельный снимок; его изменение не управляет скриптами.
- Array из int: индексы 0..N-1 либо пустой массив. Элементы — числа, а не имена и не текстовые записи.
return RunScenario();
object? RunScenario()
{
var indices = UO.GetScriptsList();
if (Truth(ArrayLength(indices) > 0))
{
var firstIndex = indices[0];
UO.Print(UO.GetScriptPath(firstIndex));
}
return null;
}
int ArrayLength(object? value) => value is System.Array array ? array.Length : 0;
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- FindNamedScript перебирает текущие индексы и возвращает первое точное совпадение отображаемого имени либо -1. Имена могут повторяться, индексы могут позже сдвинуться.
- Array из int: индексы 0..N-1 либо пустой массив. Элементы — числа, а не имена и не текстовые записи.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var index = FindNamedScript("Mining");
if (Truth(index >= 0))
{
UO.Print(Convert.ToString(index));
}
else
{
UO.Print("Name not found");
}
return null;
}
dynamic FindNamedScript(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: dynamic / Array.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetScriptsList:bridge.GetScriptsList().
Внутренний код реализации, не самостоятельный скрипт.
case "getscriptslist": return new InjectionValue(bridge.GetScriptsList().Select(value => new InjectionValue(value)).ToArray());Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Launch(object? file);
int UO.Launch(object? file, object? parameters);
int UO.Launch(object? file, object? parameters, object? workingDirectory);
int UO.Launch(object? file, object? parameters, object? workingDirectory, object? hidden);-
file— Обязательный путь/имя программы или документа; преобразуется в текст, крайние пробелы удаляются. Пустое значение даёт 0 и сообщение об ошибке. Для точного выбора программы используйте полный путь; внешние кавычки к самому file добавлять не нужно. -
workingDirectory— Необязательная рабочая папка процесса. При пропуске или пустой строке берётся папка текущего скрипта. Если у runtime нет такой папки, bridge использует текущую рабочую папку клиента. Это не всегда папка игры или EXE клиента. -
hidden— Необязательное логическое значение, по умолчанию false. true отключает открытие через оболочку ОС и запрашивает запуск без окна консоли; нужен исполняемый файл. false разрешает ассоциации документов. Сама GUI-программа всё равно может показать своё окно.
int: 1 (true), если Process.Start вернул объект процесса; иначе 0 (false). В C# проверяйте result == 1 либо result != 0; int нельзя напрямую сравнивать с true. Это не PID, не код завершения и не подтверждение выполнения работы. При исключении выводится ошибка и возвращается 0. При открытии документа через уже работающую программу ОС иногда не возвращает новый процесс: 0 в таком случае не доказывает, что документ не открылся.
- Допустимы только перегрузки от одного до четырёх аргументов в указанном порядке. Чтобы задать hidden и оставить рабочую папку по умолчанию, передайте пустую строку третьим аргументом. Преобразования file/parameters/workingDirectory в текст не проверяют существование файла заранее.
- Папка по умолчанию определяется текущим исполняемым скриптом. При hidden=true относительный путь программы сначала проверяется относительно workingDirectory. Поиск неполного имени ОС и ассоциации зависят от системы; полный путь устраняет неоднозначность. Если рабочая папка или программа недоступны, запуск может завершиться ошибкой.
- Внешний процесс работает независимо. Launch не ждёт его завершения, не читает stdout/stderr и не завершает его при остановке скрипта. true для hidden — запрос способа запуска, а не гарантия невидимости любых окон. Объект Process после запроса освобождается; сама запущенная программа продолжает работать.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Launch("loot-report.txt");
UO.Print("Launch: " + Convert.ToString(result));Параметры и ход выполнения:
- Положите существующий loot-report.txt рядом со скриптом. ОС открывает его приложением, назначенным для .txt. Main возвращает результат запроса Launch, а не содержимое отчёта и не подтверждение его прочтения.
var started = UO.Launch("loot-report.txt");
return started;Параметры и ход выполнения:
- Папка и отчёт должны существовать; замените их своими. Chr(34) заключает полный путь отчёта в двойные кавычки внутри arguments. notepad.exe должен быть доступен системе. false разрешает обычное окно редактора.
return RunScenario();
object? RunScenario()
{
var report = "C:\\UO Scripts\\loot report.txt";
var arguments = Chr(34) + report + Chr(34);
return UO.Launch("notepad.exe", arguments, "C:\\UO Scripts", false);
return null;
}
string Chr(object? value) => ((char)Convert.ToInt32(value)).ToString();Параметры и ход выполнения:
- Пример для Windows запускает встроенную cmd.exe. В папке скрипта создаётся или перезаписывается log-files.txt со списком *.log. Пустой третий аргумент сохраняет папку скрипта, true скрывает консоль. true из Main означает только запуск: файл может быть ещё не готов, а отсутствие *.log или ошибка утилиты не меняют уже полученный результат Launch.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var started = UO.Launch("cmd.exe", "/d /c dir /b *.log > log-files.txt", "", true);
if (Truth(started == 0))
{
return false;
}
return true;
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: file (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Register [Launch]. -
InjectionScript.Runtime.InjectionApiUO.CompactLaunch:CompactLaunch(values).
Вызов выполняет сохранённый delegate обработчика. Метод регистрации создаёт этот delegate при построении API.
Внутренний код реализации, не самостоятельный скрипт.
values => new InjectionValue(CompactLaunch(values))Параметры: file (Any), parameters (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Register [Launch]. -
InjectionScript.Runtime.InjectionApiUO.CompactLaunch:CompactLaunch(values).
Вызов выполняет сохранённый delegate обработчика. Метод регистрации создаёт этот delegate при построении API.
Внутренний код реализации, не самостоятельный скрипт.
values => new InjectionValue(CompactLaunch(values))Параметры: file (Any), parameters (Any), workingDirectory (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Register [Launch]. -
InjectionScript.Runtime.InjectionApiUO.CompactLaunch:CompactLaunch(values).
Вызов выполняет сохранённый delegate обработчика. Метод регистрации создаёт этот delegate при построении API.
Внутренний код реализации, не самостоятельный скрипт.
values => new InjectionValue(CompactLaunch(values))Параметры: file (Any), parameters (Any), workingDirectory (Any), hidden (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Register [Launch]. -
InjectionScript.Runtime.InjectionApiUO.CompactLaunch:CompactLaunch(values).
Вызов выполняет сохранённый delegate обработчика. Метод регистрации создаёт этот delegate при построении API.
Внутренний код реализации, не самостоятельный скрипт.
values => new InjectionValue(CompactLaunch(values))Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.PauseResumeScript(object? scriptIndex);Переключает ручную паузу одного активного запуска. Используйте для временной остановки добычи или другой процедуры без потери её текущего выполнения.
-
scriptIndex— Обязательный ScriptIndex — текущий индекс запуска: 0 обозначает первый, далее 1, 2… Получайте его через GetScriptsList; это не serial, имя файла и не результат StartScript. Отрицательный/отсутствующий индекс ничего не меняет.
void — возвращаемого значения нет. Не сравнивайте вызов с true/1. Состояние проверяйте отдельным чтением GetScriptState; результат такого чтения — 0 (нет запуска), 1 (работает), 2 (пауза).
- Работает только с запусками текущего сеанса. Открытая вкладка без выполнения не является активным запуском. Остановка не удаляет исходный файл и не отключает соединение с сервером.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
- Это переключатель, а не команда «всегда продолжить». Ручная и автоматическая паузы независимы: переключение ручной не снимает паузу разрыва связи. Код 2 не объясняет причину паузы. Если остановить таким образом собственный запуск, следующий вызов для его продолжения он сам выполнить не сможет; возобновляйте из IDE/менеджера или другого скрипта.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
for (int index = 0; index < UO.GetScriptsCount(); index++)
if (UO.GetScriptName(index) == "Worker")
{ UO.PauseResumeScript(index); break; }Параметры и ход выполнения:
- MineOre — пример отображаемого имени уже работающей процедуры. FindNamedRun возвращает первый совпавший индекс или -1. Вызывайте из другого контроллера; повторный вызов меняет ручную паузу обратно.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
var index = FindNamedRun("MineOre");
if (Truth(index >= 0))
{
UO.PauseResumeScript(index);
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Проверка == 1 ограничивает действие работающим запуском. Значение 2 не используется как указание «снять ручную паузу», потому что оно может означать отсутствие связи.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return RunScenario();
object? RunScenario()
{
var index = FindNamedRun("MineOre");
if (Truth(index >= 0))
{
if (Truth(UO.GetScriptState(index) == 1))
{
UO.PauseResumeScript(index);
}
}
return null;
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Замените абсолютный путь своим. FindFileRun сравнивает пути без учёта регистра и возвращает первый запуск этого файла; в одном файле могут выполняться несколько процедур.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var wantedPath = "D:/Game/AutoLoad/Scripts/Worker.csx";
var index = FindFileRun(wantedPath);
if (Truth(index >= 0))
{
UO.PauseResumeScript(index);
}
return null;
}
dynamic FindFileRun(dynamic wantedPath)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(Convert.ToString(ReplaceText(UO.GetScriptPath(index), Chr(92), "/")) == Convert.ToString(ReplaceText(wantedPath, Chr(92), "/"))))
{
return index;
}
}
return -1;
}
string Chr(object? value) => ((char)Convert.ToInt32(value)).ToString();
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string ReplaceText(object? value, object? oldValue, object? newValue) => (Convert.ToString(value) ?? "").Replace(Convert.ToString(oldValue) ?? "", Convert.ToString(newValue) ?? "");
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any)
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.PauseResumeScript:bridge.PauseResumeScript(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "pauseresumescript": bridge.PauseResumeScript(Arg(0)); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.SetEvent(object? name, object? stateValue);
void UO.SetEvent(object? name, object? stateValue, object? repeatOrHandler);
void UO.SetEvent(object? nameValue, object? stateValue, object? repeatValue, object? subNameValue);Включает или выключает наблюдение за изменениями состояния персонажа и позволяет выбрать одноразовую либо повторяющуюся реакцию. Например, можно один раз отменить оставшийся target после смерти или получать предупреждения о низкой выносливости. Обработчик задаётся отдельно от условия; основной скрипт должен продолжать выполнять UO.Wait.
-
name— Строка с одним из пяти имён: ChangeHitPoints, ChangeMana, ChangeStamina, Death, SeeNewPlayer. Регистр не важен; допустим префикс ev, например evChangeMana. Пробелы по краям удаляются. Числового каталога событий нет; произвольное имя не создаёт новое событие. -
nameValue— То же имя события, что name; это название первого параметра в форме с четырьмя аргументами, не дополнительное значение. -
stateValue— true/1 включает наблюдение, false/0 снимает подписку. Передавайте логические значения без кавычек. При числовом преобразовании любое ненулевое целое включает наблюдение. Отключение не ждёт и не останавливает уже запущенный обработчик. -
repeatOrHandler— Третий аргумент имеет два назначения. Нечисловая непустая строка, например "OnManaChanged", задаёт обработчик с автоматическим повторением. Число/bool задаёт только повтор: false/0 — одно срабатывание, true/1 — повторять; обработчик в этой форме не назначается. Строка "1" тоже числовая и не является именем процедуры. Для одноразового обработчика используйте четыре аргумента. -
repeatValue— В форме с четырьмя аргументами: false/0 — удалить подписку после первого обнаруженного перехода, true/1 — оставить её для следующих изменений. Одноразовая подписка снимается и тогда, когда обработчик не найден либо менеджер отклонил его запуск; не путайте обнаружение события с успешным завершением процедуры.
void — значения нет. Вызывайте отдельной строкой, без var result = и без сравнения с true/1. Завершение регистрации не подтверждает, что обработчик найден, запущен или что сервер совершил действие. Если имя процедуры не найдено при событии, вызов не происходит.
- Два аргумента: false отключает событие; true включает повторяющееся наблюдение без обработчика. Никакая процедура с совпадающим именем автоматически не подставляется. Эта форма не возвращает обнаруженный факт и не заменяет проверку HP/Mana/Dead.
- Четыре аргумента явно задают имя события, включение, повторение и обработчик. Оба логических параметра пишутся без кавычек. false/0 = one-shot: подписка снимается после первого обнаруженного перехода, а не после окончания обработчика.
- Повторная регистрация одного события заменяет его прежние настройки и запоминает текущее состояние как новую точку отсчёта. Подписки SetEvent и SetEventProc на одно нормализованное имя внутри одного скрипта используют одну запись, не накапливаются.
- ChangeHitPoints сравнивает текущее HP self с предыдущим снимком; срабатывает и при потере, и при восстановлении здоровья. ChangeMana и ChangeStamina аналогично реагируют в обе стороны. Это не только урон, расход маны или усталость.
- Death срабатывает при переходе живой → мёртвый. Регистрация уже мёртвого персонажа не вызывает обработчик сразу; повторная смерть после воскрешения может вызвать его снова.
- SeeNewPlayer сравнивает набор загруженных mobiles, исключая 0 и self. Название не означает проверку реального игрока: сюда входят NPC и существа. Один или несколько новых serial за одну проверку вызывают одну попытку запуска. Возврат ушедшего из загруженного набора mobile также может считаться новым появлением. ID не передаётся обработчику — нужные объекты надо найти отдельно.
- UO.Wait и WaitAsync делят ожидание на интервалы до 25 мс и после каждого проверяет события; UO.Wait(0) тоже выполняет проверку. Это опрос доступного состояния, а не перехват каждого сетевого пакета: быстрое изменение и возврат между проверками может быть пропущено. В вычислительном цикле без UO.Wait или после завершения основного скрипта постоянного наблюдения нет.
- Имя обработчика заранее связывается с C#-делегатом через RegisterRoutine. Callback выполняется асинхронно в этой сессии; одна задача не накладывается сама на себя. После окончания основного скрипта её дальнейшие действия запрещены.
- Подписка относится к экземпляру выполняющегося скрипта. Снимайте её в Main, который её создал: одноимённая команда внутри отдельно запущенного обработчика изменит его собственные подписки. Отмена регистрации не останавливает уже запущенный обработчик. Используйте try/
finallyдля обычного выхода или обрабатываемой ошибки; принудительная остановка также прекращает дальнейший опрос этого скрипта. - Неизвестное непустое имя события при регистрации отклоняется с системным сообщением. Пустое имя ничего не делает. Наличие обработчика проверяется только при срабатывании; ошибку в его имени лучше обнаружить заранее через SubExists и проверку скрипта в IDE.
В C# обработчик нужно явно зарегистрировать: RegisterRoutine("Handler", Handler). Изменения HP, маны и выносливости поступают через очередь native-событий; Death и SeeNewPlayer проверяются по снимкам локального мира. Прямые подписки с аргументами доступны через SubscribeEvent("UO.JournalEntry", handler) и аналогичные native-имена. Все подписки освобождаются при завершении или отмене этого выполнения.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("HealthChanged", () => UO.Print("HP changed"));
UO.SetEvent("ChangeHitPoints", true, false, "HealthChanged");
await WaitAsync(5000);Параметры и ход выполнения:
- Наблюдение длится восемь секунд. Death уже мёртвого персонажа не вызывает обработчик немедленно. Второе событие смерти после воскрешения в этом примере уже не обрабатывается.
- Обработчик проверяет активный курсор цели в момент выполнения и только тогда вызывает CancelTarget. Подготовленная очередь без активного курсора в этом примере не отменяется. Скрипт не воскрешает персонажа, не останавливает все скрипты и не завершает Main. Не запускайте пример, если хотите сохранить активную цель.
var registrationOnFirstDeath = RegisterRoutine("OnFirstDeath", OnFirstDeath);
UO.SetEvent("Death", true, false, "OnFirstDeath");
try
{
UO.Wait(8000);
}
finally
{
UO.SetEvent("Death", false);
}
void OnFirstDeath()
{
if (Truth(UO.Targeting()))
{
UO.CancelTarget();
UO.Print("Death detected: active targeting cancelled");
}
else
{
UO.Print("Death detected: no active target");
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- 24 × 250 мс — шесть секунд. 10 — наш порог в обработчике, не дополнительный аргумент SetEvent. Рост выносливости также вызывает обработчик, но при значении от 10 сообщение не выводится.
- true, "OnFatigue" отличается от true, true: последний вариант задаёт повторение без процедуры. Скрипт не повышает выносливость и не меняет скорость сервера.
return RunScenario();
object? RunScenario()
{
var registrationOnFatigue = RegisterRoutine("OnFatigue", OnFatigue);
UO.SetEvent("evChangeStamina", true, "OnFatigue");
try
{
for (int tick = (int)(1); tick <= 24; tick += (int)(1))
{
UO.Wait(250);
}
}
finally
{
UO.SetEvent("ChangeStamina", false);
}
return null;
}
void OnFatigue()
{
var staminaNow = UO.Stamina();
if (Truth(staminaNow < 10))
{
UO.Print("Stamina is " + Convert.ToString(staminaNow) + ": consider resting");
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Первые две секунды каждое обнаруженное изменение вызывает OnManaLog. Следующие три секунды используется OnLowMana. Регистрация второго обработчика сама по себе его не запускает.
- Замена не прерывает уже запущенную старую процедуру. Эти короткие обработчики не используют локальные переменные Main. При запрете наложения процедур менеджер может отклонить запуск — для такого режима проверяйте Mana прямо в Main.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var registrationOnManaLog = RegisterRoutine("OnManaLog", OnManaLog);
var registrationOnLowMana = RegisterRoutine("OnLowMana", OnLowMana);
UO.SetEvent("ChangeMana", true, true, "OnManaLog");
try
{
UO.Wait(2000);
UO.SetEvent("ChangeMana", true, true, "OnLowMana");
UO.Wait(3000);
}
finally
{
UO.SetEvent("ChangeMana", false);
}
return null;
}
void OnManaLog()
{
UO.Print("Mana now: " + Convert.ToString(UO.Mana()));
}
void OnLowMana()
{
if (Truth(UO.Mana() < 20))
{
UO.Print("Mana below 20: check the cost before casting");
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: name (Any), stateValue (Any)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.SetEvent. -
InjectionScript.Runtime.InjectionApiUO.SetEvent:SetEvent(name, stateValue, InjectionValue.True, new InjectionValue(string.Empty)).
Внутренний код реализации, не самостоятельный скрипт.
case "SetEvent": SetStateEvent(arguments); return true;Внутренний код реализации, не самостоятельный скрипт.
public void SetEvent(InjectionValue name, InjectionValue stateValue)
=> SetEvent(name, stateValue, InjectionValue.True, new InjectionValue(string.Empty));Параметры: name (Any), stateValue (Any), repeatOrHandler (Any)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.SetEvent. -
InjectionScript.Runtime.InjectionValue.ToString:repeatOrHandler.ToString(). -
InjectionScript.Runtime.NumberConversions.TryStr2Int:NumberConversions.TryStr2Int(raw, out _). -
InjectionScript.Runtime.InjectionApiUO.SetEvent:SetEvent(name, stateValue, InjectionValue.True, repeatOrHandler).
Внутренний код реализации, не самостоятельный скрипт.
case "SetEvent": SetStateEvent(arguments); return true;Внутренний код реализации, не самостоятельный скрипт.
public void SetEvent(InjectionValue name, InjectionValue stateValue, InjectionValue repeatOrHandler)
{
string raw = repeatOrHandler.ToString() ?? string.Empty;
if (!string.IsNullOrWhiteSpace(raw) && !NumberConversions.TryStr2Int(raw, out _))
SetEvent(name, stateValue, InjectionValue.True, repeatOrHandler);
else
SetEvent(name, stateValue, repeatOrHandler, new InjectionValue(string.Empty));
}Параметры: nameValue (Any), stateValue (Any), repeatValue (Any), subNameValue (Any)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.SetEvent. -
InjectionScript.Runtime.InjectionApiUO.NormalizeLegacyEventName:NormalizeLegacyEventName(nameValue.ToString()). -
InjectionScript.Runtime.InjectionValue.ToString:nameValue.ToString(). -
InjectionScript.Runtime.NumberConversions.ToInt:NumberConversions.ToInt(stateValue). -
InjectionScript.Runtime.InjectionApiUO.IsSupportedLegacyEventName:IsSupportedLegacyEventName(name). -
InjectionScript.Runtime.InjectionApiUO.SystemMessage:SystemMessage($"SetEvent: unsupported event '{name}'. Supported: SeeNewPlayer, Death, ChangeHitPoints, ChangeMana, ChangeStamina."). -
InjectionScript.Runtime.InjectionApiUO.NormalizeLegacyEventHandler:NormalizeLegacyEventHandler(subNameValue.ToString()). -
InjectionScript.Runtime.InjectionApiUO.CaptureLegacyEventSnapshot:CaptureLegacyEventSnapshot(subscription).
Внутренний код реализации, не самостоятельный скрипт.
case "SetEvent": SetStateEvent(arguments); return true;Внутренний код реализации, не самостоятельный скрипт.
public void SetEvent(InjectionValue nameValue, InjectionValue stateValue, InjectionValue repeatValue, InjectionValue subNameValue)
{
string name = NormalizeLegacyEventName(nameValue.ToString());
if (string.IsNullOrEmpty(name))
return;
bool enabled = NumberConversions.ToInt(stateValue) != 0;
eventStates[name] = enabled ? 1 : 0;
if (!enabled)
{
legacyEvents.Remove(name);
return;
}
if (!IsSupportedLegacyEventName(name))
{
eventStates[name] = 0;
legacyEvents.Remove(name);
SystemMessage($"SetEvent: unsupported event '{name}'. Supported: SeeNewPlayer, Death, ChangeHitPoints, ChangeMana, ChangeStamina.");
return;
}
var subscription = new LegacyEventSubscription
{
Name = name,
Repeat = NumberConversions.ToInt(repeatValue) != 0,
Handler = NormalizeLegacyEventHandler(subNameValue.ToString())
};
CaptureLegacyEventSnapshot(subscription);
legacyEvents[name] = subscription;
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.SetEventProc(object? eventname, object? procname);Назначает процедуру, которую клиент будет запускать при изменении наблюдаемого состояния: например, при потере здоровья, изменении маны или появлении нового mobile. Позволяет отделить реакцию от основного цикла. Регистрация сама ничего не запускает: Основной скрипт должен оставаться активным; C#-контрольные точки, WaitAsync и UO.Wait обрабатывают события.
-
eventname— Строка с одним из пяти имён: ChangeHitPoints, ChangeMana, ChangeStamina, Death, SeeNewPlayer. Регистр не важен; допустим префикс ev, например evChangeMana. Пробелы по краям удаляются. Числового каталога событий нет; произвольное имя не создаёт новое событие.
void — значения нет. Вызывайте отдельной строкой, без var result = и без сравнения с true/1. Завершение регистрации не подтверждает, что обработчик найден, запущен или что сервер совершил действие. Если имя процедуры не найдено при событии, вызов не происходит.
- Оба аргумента обязательны. Подписка повторяющаяся: новые обнаруженные изменения вызывают новые попытки запуска. В одном выполняющемся скрипте на одно нормализованное имя события назначается один обработчик; повторная регистрация заменяет его и обновляет начальный снимок. SetEventProc(event, "") снимает подписку в этом же скрипте. Для одноразовой реакции используйте SetEvent(event, true, false, "Handler").
- ChangeHitPoints сравнивает текущее HP self с предыдущим снимком; срабатывает и при потере, и при восстановлении здоровья. ChangeMana и ChangeStamina аналогично реагируют в обе стороны. Это не только урон, расход маны или усталость.
- Death срабатывает при переходе живой → мёртвый. Регистрация уже мёртвого персонажа не вызывает обработчик сразу; повторная смерть после воскрешения может вызвать его снова.
- SeeNewPlayer сравнивает набор загруженных mobiles, исключая 0 и self. Название не означает проверку реального игрока: сюда входят NPC и существа. Один или несколько новых serial за одну проверку вызывают одну попытку запуска. Возврат ушедшего из загруженного набора mobile также может считаться новым появлением. ID не передаётся обработчику — нужные объекты надо найти отдельно.
- UO.Wait и WaitAsync делят ожидание на интервалы до 25 мс и после каждого проверяет события; UO.Wait(0) тоже выполняет проверку. Это опрос доступного состояния, а не перехват каждого сетевого пакета: быстрое изменение и возврат между проверками может быть пропущено. В вычислительном цикле без UO.Wait или после завершения основного скрипта постоянного наблюдения нет.
- Имя обработчика заранее связывается с C#-делегатом через RegisterRoutine. Callback выполняется асинхронно в этой сессии; одна задача не накладывается сама на себя. После окончания основного скрипта её дальнейшие действия запрещены.
- Подписка относится к экземпляру выполняющегося скрипта. Снимайте её в Main, который её создал: одноимённая команда внутри отдельно запущенного обработчика изменит его собственные подписки. Отмена регистрации не останавливает уже запущенный обработчик. Используйте try/
finallyдля обычного выхода или обрабатываемой ошибки; принудительная остановка также прекращает дальнейший опрос этого скрипта. - Неизвестное непустое имя события при регистрации отклоняется с системным сообщением. Пустое имя ничего не делает. Наличие обработчика проверяется только при срабатывании; ошибку в его имени лучше обнаружить заранее через SubExists и проверку скрипта в IDE.
В C# обработчик нужно явно зарегистрировать: RegisterRoutine("Handler", Handler). Изменения HP, маны и выносливости поступают через очередь native-событий; Death и SeeNewPlayer проверяются по снимкам локального мира. Прямые подписки с аргументами доступны через SubscribeEvent("UO.JournalEntry", handler) и аналогичные native-имена. Все подписки освобождаются при завершении или отмене этого выполнения.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("HealthChanged", () => UO.Print("HP changed"));
UO.SetEventProc("ChangeHitPoints", "HealthChanged");
await WaitAsync(5000);Параметры и ход выполнения:
- ChangeHitPoints наблюдает HP своего персонажа. OnHealthChanged — имя метод ниже/выше Main в том же загруженном файле. UO.Wait обслуживает события; пустой второй аргумент отключает повторения.
- Обработчик только предупреждает и не выбирает лечение автоматически. При изменении HP 60 → 50 → 70 выполняются две реакции; это не счётчик ударов.
var registrationOnHealthChanged = RegisterRoutine("OnHealthChanged", OnHealthChanged);
UO.SetEventProc("ChangeHitPoints", "OnHealthChanged");
try
{
for (int tick = (int)(1); tick <= 40; tick += (int)(1))
{
UO.Wait(250);
}
}
finally
{
UO.SetEventProc("ChangeHitPoints", "");
}
void OnHealthChanged()
{
var hp = UO.HP();
if (Truth(hp < 40))
{
UO.Print("Low health: " + Convert.ToString(hp) + ". Check healing or retreat.");
}
else
{
UO.Print("Health changed: " + Convert.ToString(hp));
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- evChangeMana и ChangeMana — одно событие. Здесь две независимые подписки и два разных обработчика, а не два обработчика на одно имя. Пороги 20 и 10 можно изменить.
- Ожидание длится 5 секунд. Восстановление ресурсов тоже обнаруживается, но if не выдаёт предупреждение, когда значение уже выше порога.
return RunScenario();
object? RunScenario()
{
var registrationOnManaChanged = RegisterRoutine("OnManaChanged", OnManaChanged);
var registrationOnStaminaChanged = RegisterRoutine("OnStaminaChanged", OnStaminaChanged);
UO.SetEventProc("evChangeMana", "OnManaChanged");
UO.SetEventProc("ChangeStamina", "OnStaminaChanged");
try
{
for (int tick = (int)(1); tick <= 20; tick += (int)(1))
{
UO.Wait(250);
}
}
finally
{
UO.SetEventProc("ChangeMana", "");
UO.SetEventProc("ChangeStamina", "");
}
return null;
}
void OnManaChanged()
{
if (Truth(UO.Mana() < 20))
{
UO.Print("Mana below 20: postpone expensive spells");
}
}
void OnStaminaChanged()
{
if (Truth(UO.Stamina() < 10))
{
UO.Print("Stamina below 10: consider a movement break");
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- SeeNewPlayer обнаруживает появление serial в загруженном наборе mobiles, включая NPC. Одновременная загрузка пяти существ не гарантирует пять вызовов.
- GetMobiles() — отдельное чтение актуального набора, не ID из события. Чтобы выбрать врага, нужны явные условия; пример намеренно никого не атакует.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var registrationOnMobileAppeared = RegisterRoutine("OnMobileAppeared", OnMobileAppeared);
UO.SetEventProc("SeeNewPlayer", "OnMobileAppeared");
try
{
UO.Wait(5000);
}
finally
{
UO.SetEventProc("SeeNewPlayer", "");
}
UO.Wait(1000);
return null;
}
void OnMobileAppeared()
{
var mobiles = UO.GetMobiles();
UO.Print("Loaded mobiles now: " + Convert.ToString(ArrayLength(mobiles)));
}
int ArrayLength(object? value) => value is System.Array array ? array.Length : 0;
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: eventname (Any), procname (Any)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(1). -
InjectionScript.Runtime.InjectionApiUO.SetEvent:SetEvent(arguments[0], InjectionValue.False). -
InjectionScript.Runtime.InjectionApiUO.SetEvent:SetEvent(arguments[0], InjectionValue.True, InjectionValue.True, arguments[1]).
Внутренний код реализации, не самостоятельный скрипт.
case "SetEventProc":
SetStateEvent([arguments[0], !string.IsNullOrWhiteSpace(Convert.ToString(arguments[1])), true, arguments[1]]);
return true;Внутренний код реализации, не самостоятельный скрипт.
case "seteventproc":
{
if (string.IsNullOrWhiteSpace(Text(1)))
SetEvent(arguments[0], InjectionValue.False);
else
SetEvent(arguments[0], InjectionValue.True, InjectionValue.True, arguments[1]);
return InjectionValue.Unit;
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.SetPauseScriptOnDisconnectStatus(object? value);Меняет правило паузы скриптов при потере соединения.
-
value— 0 выключает; любое ненулевое целое включает.
void — значения нет. Вызывайте отдельной строкой; завершение не подтверждает действие сервера.
- SetPauseScriptOnDisconnectStatus задаёт _manager.PauseScriptsOnDisconnect = enabled != 0. Уже запущенные скрипты не получают здесь команду PauseResumeScript.
- Меняет настройку клиента. Значение не является результатом проверки соединения и не подтверждает обработку сервером.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Команда вызывается отдельной строкой. Сообщение перед ней показывает начало вызова, а не подтверждение действия сервера.
UO.Print("Calling UO.SetPauseScriptOnDisconnectStatus");
UO.SetPauseScriptOnDisconnectStatus(1);Параметры и ход выполнения:
- Меняет правило паузы скриптов при потере соединения.
UO.SetPauseScriptOnDisconnectStatus(1);Параметры и ход выполнения:
- SetPauseScriptOnDisconnectStatus задаёт _manager.PauseScriptsOnDisconnect = enabled != 0. Уже запущенные скрипты не получают здесь команду PauseResumeScript.
return RunScenario();
object? RunScenario()
{
UO.SetPauseScriptOnDisconnectStatus(0);
return null;
}Параметры и ход выполнения:
- Меняет настройку клиента. Значение не является результатом проверки соединения и не подтверждает обработку сервером.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
ApplyMode(1);
return null;
}
void ApplyMode(dynamic mode)
{
UO.SetPauseScriptOnDisconnectStatus(mode);
}
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: value (Any)
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.SetPauseScriptOnDisconnectStatus:bridge.SetPauseScriptOnDisconnectStatus(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "setpausescriptondisconnectstatus": bridge.SetPauseScriptOnDisconnectStatus(Arg(0)); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.SetScriptName(object? scriptIndex, object? value);Меняет отображаемое имя одного активного запуска. Помогает различать выполняющиеся задачи в списке и через GetScriptName.
-
scriptIndex— Обязательный ScriptIndex — текущий индекс запуска: 0 обозначает первый, далее 1, 2… Получайте его через GetScriptsList; это не serial, имя файла и не результат StartScript. Отрицательный/отсутствующий индекс ничего не меняет. -
value— Обязательный Value — новое имя, преобразуемое в строку. Пробелы допустимы; пустая строка также допустима. Это подпись текущего запуска, а не новое имя файла или процедуры в исходнике.
void — возвращаемого значения нет. Не сравнивайте вызов с true/1. Состояние проверяйте отдельным чтением GetScriptState; результат такого чтения — 0 (нет запуска), 1 (работает), 2 (пауза).
- Работает только с запусками текущего сеанса. Открытая вкладка без выполнения не является активным запуском. Остановка не удаляет исходный файл и не отключает соединение с сервером.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
for (int index = 0; index < UO.GetScriptsCount(); index++)
if (UO.GetScriptName(index) == "Worker")
{ UO.SetScriptName(index, "Worker renamed"); break; }Параметры и ход выполнения:
- MineOre ищется в активных запусках, Mining — новая подпись. Имена внутри кавычек придуманы пользователем и могут быть заменены.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
var index = FindNamedRun("MineOre");
if (Truth(index >= 0))
{
UO.SetScriptName(index, "Mining");
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Замените wantedPath своим абсолютным путём. Меняется подпись первого активного запуска этого файла, а файл на диске остаётся на прежнем месте.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return RunScenario();
object? RunScenario()
{
var wantedPath = "D:/Game/AutoLoad/Scripts/Worker.csx";
var index = FindFileRun(wantedPath);
if (Truth(index >= 0))
{
UO.SetScriptName(index, "Worker A");
}
return null;
}
dynamic FindFileRun(dynamic wantedPath)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(Convert.ToString(ReplaceText(UO.GetScriptPath(index), Chr(92), "/")) == Convert.ToString(ReplaceText(wantedPath, Chr(92), "/"))))
{
return index;
}
}
return -1;
}
string Chr(object? value) => ((char)Convert.ToInt32(value)).ToString();
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string ReplaceText(object? value, object? oldValue, object? newValue) => (Convert.ToString(value) ?? "").Replace(Convert.ToString(oldValue) ?? "", Convert.ToString(newValue) ?? "");Параметры и ход выполнения:
- GetScriptState = 2 добавляет текст paused к имени. Это однократная подпись: она не обновляется автоматически после продолжения и не управляет самой паузой.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var index = FindNamedRun("Mining");
if (Truth(index >= 0))
{
var newName = "Mining";
if (Truth(UO.GetScriptState(index) == 2))
{
newName = "Mining (paused)";
}
UO.SetScriptName(index, newName);
}
return null;
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any), value (Any)
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.SetScriptName:bridge.SetScriptName(Arg(0), Text(1)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(1).
Внутренний код реализации, не самостоятельный скрипт.
case "setscriptname": bridge.SetScriptName(Arg(0), Text(1)); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.StartScript(object? scriptPath);int: количество активных запусков после принятого запуска; 65535 (0xFFFF) = ошибка запуска. Это не индекс нового скрипта, не bool и не результат завершения.
- Учитываются выполняющиеся и приостановленные запуски; завершённые и получившие запрос отмены исключаются. Работающий скрипт обычно учитывает и себя. Просто загруженная вкладка IDE запуском не считается.
- Индексы — текущие позиции в порядке запуска. Запуск/остановка скриптов могут сдвинуть позиции. Разные вызовы не образуют общий атомарный снимок; перед последующей командой управления перечитайте список.
- GetScriptsList даёт индексы, GetScriptsCount — количество, GetScriptState — код из трёх состояний. Не подменяйте одно другим и не считайте любой ненулевой результат значением true.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.StartScript("Scripts/Worker.csx");
UO.Print("StartScript: " + Convert.ToString(result));Параметры и ход выполнения:
- Запускайте приведённый C#-скрипт. Число 0, где оно передано, обозначает индекс; пустые скобки означают отсутствие аргументов. Текст Print — только сообщение примера.
- Перед примерами отдельно создайте указанные файлы Worker.csx. Ошибочный/недоступный путь, неподходящая Main, отключённый C# или запрет параллельного запуска дают отказ. Если прежний запуск ещё останавливается, возможен отложенный повтор; принятие запуска не означает завершения. Короткий скрипт может закончить работу ещё до чтения возвращённого количества.
- int: количество активных запусков после принятого запуска; 65535 (0xFFFF) = ошибка запуска. Это не индекс нового скрипта, не bool и не результат завершения.
- Обязательный ScriptPath — строка. Относительный путь начинается в папке AutoLoad этого клиента; абсолютный путь допустим. Путь с пробелами заключайте в кавычки. Нужен .csx с кодом на верхнем уровне либо обычный .cs/.csproj с поддерживаемой точкой входа C#.
var count = UO.StartScript("Scripts/Worker.csx");
if (Truth(count==65535))
{
UO.Print("launch failed");
}
else
{
UO.Print("Active executions: " + Convert.ToString(count));
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Это отдельный пример совместного использования команд. Индексация массива начинается с нуля; перед обращением проверяйте длину. UO.Wait(250), где он используется, ждёт 250 миллисекунд.
- Перед примерами отдельно создайте указанные файлы Worker.csx. Ошибочный/недоступный путь, неподходящая Main, отключённый C# или запрет параллельного запуска дают отказ. Если прежний запуск ещё останавливается, возможен отложенный повтор; принятие запуска не означает завершения. Короткий скрипт может закончить работу ещё до чтения возвращённого количества.
- int: количество активных запусков после принятого запуска; 65535 (0xFFFF) = ошибка запуска. Это не индекс нового скрипта, не bool и не результат завершения.
- Обязательный ScriptPath — строка. Относительный путь начинается в папке AutoLoad этого клиента; абсолютный путь допустим. Путь с пробелами заключайте в кавычки. Нужен .csx с кодом на верхнем уровне либо обычный .cs/.csproj с поддерживаемой точкой входа C#.
return RunScenario();
object? RunScenario()
{
var count = UO.StartScript("Scripts/My Worker.csx");
if (Truth(count != 65535))
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
UO.Print(Convert.ToString(index) + ": " + UO.GetScriptPath(index));
}
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Под Main приведена функция целиком. Её параметры и результат объясняются отдельно от API-команды, которую она вызывает.
- TryStartCSharp сравнивает результат с 65535 и возвращает true/false. Она не ждёт завершения и не превращает количество в индекс.
- int: количество активных запусков после принятого запуска; 65535 (0xFFFF) = ошибка запуска. Это не индекс нового скрипта, не bool и не результат завершения.
- Обязательный ScriptPath — строка. Относительный путь начинается в папке AutoLoad этого клиента; абсолютный путь допустим. Путь с пробелами заключайте в кавычки. Нужен .csx с кодом на верхнем уровне либо обычный .cs/.csproj с поддерживаемой точкой входа C#.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
if (Truth(TryStartCSharp("Scripts/Worker.csx")))
{
UO.Print("launch accepted");
}
else
{
UO.Print("check file, Main and execution settings");
}
return null;
}
dynamic TryStartCSharp(dynamic fileName)
{
var count = UO.StartScript(fileName);
return Truth(count != 65535);
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptPath (Any)
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.StartScript:bridge.StartScript(Text(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(0).
Внутренний код реализации, не самостоятельный скрипт.
case "startscript": return new InjectionValue(bridge.StartScript(Text(0)));Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.StopAllScripts();Параметров нет.
void — возвращаемого значения нет. Не сравнивайте вызов с true/1. Состояние проверяйте отдельным чтением GetScriptState; результат такого чтения — 0 (нет запуска), 1 (работает), 2 (пауза).
- Работает только с запусками текущего сеанса. Открытая вкладка без выполнения не является активным запуском. Остановка не удаляет исходный файл и не отключает соединение с сервером.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
- Аргументов нет. Отменяются выполняющиеся и приостановленные процедуры, ожидающие запуска запросы и очередь повторных запусков. Вызывающий скрипт тоже получает отмену: не помещайте обязательное сохранение/отчёт после этой команды. Другие профили и процессы не затрагиваются.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Команда вызывается отдельной строкой. Сообщение перед ней показывает начало вызова, а не подтверждение действия сервера.
UO.Print("Calling UO.StopAllScripts");
UO.StopAllScripts();Параметры и ход выполнения:
- У команды пустые скобки. Выполните нужное сохранение до вызова. Сам контроллер тоже будет остановлен.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
UO.StopAllScripts();Параметры и ход выполнения:
- Connected проверяет вход в мир, Dead — смерть. StopAllScripts вызывается только при выполнении обоих условий; пример проверяет их один раз.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return RunScenario();
object? RunScenario()
{
if (Truth(UO.Connected()))
{
if (Truth(UO.Dead()))
{
UO.StopAllScripts();
}
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- 5000 — миллисекунды в UO.Wait, а не параметр StopAllScripts. Ручная или автоматическая пауза контроллера может отложить выполнение; это не независимый таймер.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var delayMs = 5000;
UO.Wait(delayMs);
UO.StopAllScripts();
return null;
}
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.StopAllScripts:bridge.StopAllScripts().
Внутренний код реализации, не самостоятельный скрипт.
case "stopallscripts": bridge.StopAllScripts(); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.StopScript(object? scriptIndex);Запрашивает отмену одного активного запуска, в том числе стоящего на паузе. Используйте, когда работу этого запуска нужно закончить, а не продолжить позже.
-
scriptIndex— Обязательный ScriptIndex — текущий индекс запуска: 0 обозначает первый, далее 1, 2… Получайте его через GetScriptsList; это не serial, имя файла и не результат StartScript. Отрицательный/отсутствующий индекс ничего не меняет.
void — возвращаемого значения нет. Не сравнивайте вызов с true/1. Состояние проверяйте отдельным чтением GetScriptState; результат такого чтения — 0 (нет запуска), 1 (работает), 2 (пауза).
- Работает только с запусками текущего сеанса. Открытая вкладка без выполнения не является активным запуском. Остановка не удаляет исходный файл и не отключает соединение с сервером.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
- Отмена кооперативная: будит ожидание паузы и проверяется движком; уже отправленные действия серверу не отменяются. Отменённый запуск сразу исключается из активного списка, хотя освобождение ресурсов ещё может продолжаться. Не проверяйте завершение по прежнему индексу: под ним уже может быть другой запуск.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
for (int index = 0; index < UO.GetScriptsCount(); index++)
if (UO.GetScriptName(index) == "Worker")
{ UO.StopScript(index); break; }Параметры и ход выполнения:
- MineOre — имя запуска. -1 не передаётся в StopScript. После остановки сохранённый индекс больше не используется.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
var index = FindNamedRun("MineOre");
if (Truth(index >= 0))
{
UO.StopScript(index);
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Код 2 выбирает приостановленный запуск. StopScript завершает его, а не снимает паузу; остальные задачи продолжаются.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return RunScenario();
object? RunScenario()
{
var index = FindNamedRun("MineOre");
if (Truth(index >= 0))
{
if (Truth(UO.GetScriptState(index) == 2))
{
UO.StopScript(index);
}
}
return null;
}
dynamic FindNamedRun(dynamic wanted)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(UO.GetScriptName(index) == wanted))
{
return index;
}
}
return -1;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Абсолютный путь выбирает первый активный запуск файла. Это не удаление файла и не остановка всех процедур из этого файла.
- Индексы динамические: после завершения другого запуска позиции могут сдвинуться. Несколько API-вызовов не являются атомарной операцией. Примеры рассчитаны на отсутствие параллельного изменения списка; ищите нужный запуск заново перед действием и не храните индекс через UO.Wait.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var wantedPath = "D:/Game/AutoLoad/Scripts/Worker.csx";
var index = FindFileRun(wantedPath);
if (Truth(index >= 0))
{
UO.StopScript(index);
}
return null;
}
dynamic FindFileRun(dynamic wantedPath)
{
var indices = UO.GetScriptsList();
foreach (var index in indices)
{
if (Truth(Convert.ToString(ReplaceText(UO.GetScriptPath(index), Chr(92), "/")) == Convert.ToString(ReplaceText(wantedPath, Chr(92), "/"))))
{
return index;
}
}
return -1;
}
string Chr(object? value) => ((char)Convert.ToInt32(value)).ToString();
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string ReplaceText(object? value, object? oldValue, object? newValue) => (Convert.ToString(value) ?? "").Replace(Convert.ToString(oldValue) ?? "", Convert.ToString(newValue) ?? "");
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: scriptIndex (Any)
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.StopScript:bridge.StopScript(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
case "stopscript": bridge.StopScript(Arg(0)); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.SubExists(object? subrutineName);Проверяет, зарегистрирован ли C#-делегат с указанным именем в текущем выполнении. Это реестр callback-функций данной сессии, без автоматического поиска произвольных методов через reflection; явно загруженные файловые входы также доступны по ключу.
-
subrutineName— строковое имя, заданное RegisterRoutine. Пробелы по краям удаляются; поиск зарегистрированного имени не зависит от регистра.
int: 1 — условие выполнено, 0 — не выполнено. Сохраните результат одного вызова, если он нужен нескольким проверкам.
- Регистрация и задачи принадлежат одному выполнению. Другой персонаж, профиль или последующий запуск имеет собственный реестр.
- RegisterRoutine принимает
Action,Func<Task>либо делегат с массивом строковых аргументов для Exec. Удаление регистрации не запускает код и исключает дальнейший поиск имени. - Основной скрипт должен оставаться активным, пока нужны его помощники: после его окончания задачи отменяются, а регистрации и подписки освобождаются.
- FunRunning не является индексом менеджера. GetScriptsList и GetScriptState описывают самостоятельные запуски файлов; локальный callback отдельного индекса не получает.
- Ошибка callback передаётся основному скрипту на следующей проверке. WaitAsync, UO.Wait и инструментированные C#-циклы поддерживают паузу, отмену и обработку очереди событий.
Помимо локальных делегатов, текущий менеджер поддерживает явно загруженные C#-входы с ключом вроде Child.csx::Main. SubExists и FunRunning принимают такой ключ; CallSub запускает файл без Args, а Exec("exec Child.csx::Main 'north gate' 42") передаёт Args. Ключ с пробелами заключается в кавычки внутри Exec. Уникальное короткое имя допустимо, неоднозначное имя не выбирает случайный файл. Локальная регистрация имеет приоритет. Файловый запуск получает собственный контекст и время жизни в текущем мире/менеджере; локальные делегаты принадлежат выполнению, которое их зарегистрировало.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
RegisterRoutine("Hello", () => UO.Print("Hello"));
UO.Print("Registered flag: " + UO.SubExists("Hello"));Параметры и ход выполнения:
- Команда возвращает int: в C# проверяйте result != 0 или result == 1; прямое сравнение с true недопустимо. Определение WeightWatch приведено ниже и регистрируется через RegisterRoutine перед вызовом команды.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
if (Truth(Truth(UO.SubExists("WeightWatch")) == true))
{
UO.CallSub("WeightWatch");
}
while (UO.FunRunning("WeightWatch") != 0) await WaitAsync(25);
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- WeightWatch может быть загружен из другого файла. Если его нет, выбирается объявленный здесь ManaWatch. Если основной найден, но не может запуститься, автоматического перехода к запасному не будет.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var registrationManaWatch = RegisterRoutine("ManaWatch", ManaWatch);
if (Truth(UO.SubExists("WeightWatch") == 1))
{
UO.CallSub("WeightWatch");
}
else if (Truth(UO.SubExists("ManaWatch")))
{
UO.CallSub("ManaWatch");
}
while (UO.FunRunning("ManaWatch") != 0)
await WaitAsync(25);
return null;
}
void ManaWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Mana: " + Convert.ToString(UO.Mana()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- HaveMonitors проверяет два имени через &&. При отсутствии хотя бы одного Main не вызывает ни одну задачу. Проверяется комплект определений, а не гарантия успешного одновременного запуска.
- Сохраните пример как отдельный файл, загрузите его в IDE/менеджер и запускайте Main, чтобы остальные процедуры попали в каталог. WeightWatch/ManaWatch — полностью определённые здесь учебные процедуры: три замера веса/маны с интервалом UO.Wait(1000), то есть 1000 мс, вывод только при входе в мир. Это не постоянный мониторинг; пауза может растянуть время. Для примера с двумя задачами должен быть разрешён одновременный запуск процедур.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
var registrationWeightWatch = RegisterRoutine("WeightWatch", WeightWatch);
var registrationManaWatch = RegisterRoutine("ManaWatch", ManaWatch);
if (Truth(HaveMonitors()))
{
UO.CallSub("WeightWatch");
UO.CallSub("ManaWatch");
}
while (UO.FunRunning("WeightWatch") != 0 || UO.FunRunning("ManaWatch") != 0)
await WaitAsync(25);
return null;
}
dynamic HaveMonitors()
{
return UO.SubExists("WeightWatch") != 0 && UO.SubExists("ManaWatch") != 0;
}
void WeightWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Weight: " + Convert.ToString(UO.Weight()));
}
UO.Wait(1000);
}
}
void ManaWatch()
{
dynamic sample = 0;
for (sample = (int)(1); sample <= 3; sample += (int)(1))
{
if (Truth(UO.Connected()))
{
UO.Print("Mana: " + Convert.ToString(UO.Mana()));
}
UO.Wait(1000);
}
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
private IDisposable RegisterRoutine(string name, Action handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Action<string[]> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
private IDisposable RegisterRoutine(string name, Func<string[], Task> handler) => global::ClassicUO.CSharp.CSharpScriptContext.Current.RegisterRoutine(name, handler);
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: subrutineName (String)
Результат: int / Integer.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.SubExists. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.SubExists:bridge.SubExists(subrutineName).
Внутренний код реализации, не самостоятельный скрипт.
case "SubExists":
string requested = Convert.ToString(arguments[0]) ?? "";
result = Exists(requested) || events is ICSharpScriptHost known && known.HasCSharpScript(requested) ? 1 : 0;
return true;Внутренний код реализации, не самостоятельный скрипт.
public int SubExists(string subrutineName) => bridge.SubExists(subrutineName) ? 1 : 0;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.Terminate();
void UO.Terminate(object? subrutineName);-
subrutineName— Необязательная строка. Без аргумента или с пустой строкой выбирается последний запущенный файл; "all" запрашивает отмену всех запусков. Для файлов C# используйте точный ключ из каталога, напримерharvest.csx::Main. Произвольное имя локального callback, напримерHarvest, работает только после явной регистрации черезRegisterRoutine. Сам файл имеет один входMain; отдельные методы класса не становятся автоматически отдельными запускаемыми процедурами.
void: команда не возвращает число и не ожидает завершения рабочего потока. Она немедленно запрашивает отмену. Исполнение прекращается на ближайшей проверке отмены; паузы, точки останова и встроенные ожидания прерываются. Серверные действия, уже отправленные до отмены, не откатываются.
Значение UO.FunRunning(name) == 0 возможно также сразу после запроса отмены. Оно не означает, что блок finally предыдущего callback уже завершился. Повторный CallSub или Exec того же локального имени пропускается, пока прежний обработчик фактически не завершит работу.
- UO.Terminate() выбирает процедуру по порядку запуска, а не по имени, строке редактора, времени последнего действия или порядку отображения. Поставленная на паузу процедура также считается запущенной.
- Очищается принадлежащий этому запуску локальный прицел и отменяется оставшийся автоматический маршрут. Отмена движения выполняется на игровом потоке; если маршрут уже заменён другим запуском или пользователем, прежний владелец его не останавливает. Отправленные серверу шаги не отзываются.
- Команда остаётся доступной при включённой настройке одного одновременного запуска. Отменённая процедура освобождает место только после очистки своего рабочего потока; до этого новый запуск пропускается.
- При остановке по имени также отменяются соответствующие отложенные запуски. Завершённые процедуры не изменяются. Об отсутствии подходящего запуска клиент сообщает в статусе. Зависший вызов стороннего нативного плагина, который не поддерживает отмену, нельзя безопасно прервать принудительным уничтожением потока.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Для файлов C# используйте точный ключ из каталога, например harvest.csx::Main. Произвольное имя локального callback, например Harvest, работает только после явной регистрации через RegisterRoutine. Сам файл имеет один вход Main; отдельные методы класса не становятся автоматически отдельными запускаемыми процедурами.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
UO.Terminate("harvest.csx::Main");
UO.Print("Cancellation requested for harvest.csx::Main");Пример запрашивает отмену уже запущенного harvest.csx::Main. Сообщение не подтверждает завершение его finally или откат игровых действий.
var procedureName = "harvest.csx::Main";
UO.Terminate(procedureName);
UO.Print("Cancellation requested for harvest.csx::Main");Точный ключ harvest.csx::Main отличается от heal.csx::Main. Замените демонстрационный ключ на ключ своего загруженного файла; произвольные суффиксы вроде #2 не создают второй вход.
return RunScenario();
object? RunScenario()
{
var procedureKey = "harvest.csx::Main";
UO.Terminate(procedureKey);
UO.Print("Cancellation requested: " + procedureKey);
return null;
}Строка terminate harvest.csx::Main передаёт тот же ключ через UO.Exec. Ключ с пробелами нужно заключить в кавычки внутри командной строки.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var command = "terminate harvest.csx::Main";
UO.Exec(command);
UO.Print("Stop command sent");
return null;
}
}Параметры и ход выполнения:
- Форма без аргументов выбирает последний запущенный скрипт, включая поставленный на паузу. Это политика примера, а не обязательная реакция на низкое здоровье; сообщение выводится до запроса отмены.
if (UO.GetHP() <= 30)
{
UO.Print("Low health: requesting cancellation of the most recent run");
UO.Terminate();
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Terminate. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.Terminate:bridge.Terminate(string.Empty).
Внутренний код реализации, не самостоятельный скрипт.
public void Terminate() => bridge.Terminate(string.Empty);Параметры: subrutineName (String)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpCallbacks.TryInvoke. -
InjectionScript.Runtime.InjectionApiUO.Terminate. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.Terminate:bridge.Terminate(subrutineName).
Внутренний код реализации, не самостоятельный скрипт.
case "Terminate" when arguments.Length == 1:
string routine = Convert.ToString(arguments[0]) ?? "";
if (Exists(routine)) { Cancel(routine); return true; }
if (Cancel(routine)) return true;
return false;Внутренний код реализации, не самостоятельный скрипт.
public void Terminate(string subrutineName) => bridge.Terminate(subrutineName);Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.TerminateAll();Параметров нет.
void: результата нет. Команда запрашивает отмену всех текущих запусков и возвращает управление вызывающему коду, если он сам не был отменён. Очистка рабочих потоков выполняется после срабатывания их проверок отмены.
- Точный синтаксис — UO.TerminateAll(), без пробела внутри имени и без аргументов. UO.Terminate("all") поддерживается как совместимая альтернативная запись.
- Останавливаются работающие процедуры, процедуры на ручной паузе и на точке останова, встроенные ожидания и зарегистрированные отложенные запуски. Повторный вызов при отсутствии работы безопасен.
- Снятие локальных прицелов и автоматических маршрутов учитывает их владельцев. Оставшийся маршрут остановленного скрипта отменяется на игровом потоке; новый маршрут пользователя, заменивший его, сохраняется. Уже отправленные пакеты движения не отменяются.
- Отмена не откатывает уже отправленные серверу действия. Код сторонних нативных плагинов без поддержки отмены нельзя безопасно уничтожить вместе с потоком. Новые явные запуски после выполнения команды разрешены; при включённой галочке они ждут освобождения места в том смысле, что попытка до завершения очистки пропускается, а не ставится в очередь.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Команда вызывается отдельной строкой. Сообщение перед ней показывает начало вызова, а не подтверждение действия сервера.
UO.Print("Calling UO.TerminateAll");
UO.TerminateAll();Параметры и ход выполнения:
- У TerminateAll нет параметров. Условие UO.Dead() проверяет смерть персонажа перед очередной итерацией.
- При выполнении условия отменяются и текущий Main, и остальные запуски C#. Сообщение Print расположено до остановки, поскольку после неё код этой процедуры прекращается.
- WaitAsync(250) задаёт паузу 250 миллисекунд между проверками в этом примере. Команда остановки не меняет длительность обычных пауз скрипта.
for (int cycle = (int)(1); cycle <= 10; cycle += (int)(1))
{
if (Truth(UO.Dead()))
{
UO.Print("Character is dead: stopping all C# scripts");
UO.TerminateAll();
}
await Delay(250);
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- В этой альтернативной записи используется UO.Terminate с одним параметром subrutineName="all". Это эквивалент UO.TerminateAll().
- Строка all — специальное значение, а не имя процедуры, которое требуется объявить. Отменяется и EmergencyStop.
- Для аварийной игровой клавиши используйте однострочную команду из первого примера: отдельная процедура EmergencyStop сама подчиняется запрету параллельных запусков.
return RunScenario();
object? RunScenario()
{
UO.Print("Stopping all C# scripts");
UO.Terminate("all");
return null;
}Параметры и ход выполнения:
- GetSerial сохраняет serial обязательного объекта, здесь собственного рюкзака. Exists=0 означает, что этот объект сейчас неизвестен клиенту.
- TerminateAll вызывается без аргументов только при нарушении выбранного условия. Эта политика останавливает все процедуры, а не только работу с данным рюкзаком.
- Сначала выводится причина остановки. После запроса отмены текущая процедура тоже прекращается; рассчитывать на выполнение следующего действия нельзя.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var bag = UO.GetSerial("backpack");
if (Truth(UO.Exists(bag) == 0))
{
UO.Print("Required backpack is unavailable: stopping all scripts");
UO.TerminateAll();
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}Параметры и ход выполнения:
- При отсутствии соединения выбирается остановка всех запусков. Команда не возвращает количество отменённых скриптов и отменяет также текущий запуск.
if (UO.Connected() == 0)
{
UO.Print("Disconnected: requesting cancellation of every active script");
UO.TerminateAll();
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: void / Unit.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.TerminateAll. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.Terminate:bridge.Terminate("all").
Внутренний код реализации, не самостоятельный скрипт.
public void TerminateAll() => bridge.Terminate("all");Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Time();Читает местное время суток компьютера числом HHMMSS. Удобна для выбора разрешённого времени работы, не для измерения длительности.
Параметров нет.
int HHMMSS, 0..235959 с допустимыми минутами и секундами. 07:29:35 -> 72935; полночь -> 0. Ноль — допустимое время, а не ошибка и не логический флаг false.
- Параметров нет, форм с аргументами нет. Пустые скобки только читают время: вызов не ждёт, не запускает таймер и не отправляет пакеты в игру.
- RealTimeSource.Now читает DateTime.Now: местную дату/время компьютера, не UTC, не время шарда и не игровые часы. Часовой пояс, летнее время и ручной перевод часов влияют на результат. Каждый вызов фиксирует отдельный момент.
- Начальные нули не сохраняются, миллисекунд нет. Численно 13:00:00 минус 12:59:59 даёт 4041, хотя прошла одна секунда. В полночь значение снова становится нулём.
- Не вычитайте календарные коды для расчёта задержки. Используйте Timer() и две отметки одного запуска. Календарные часы могут перевестись назад.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Time();
UO.Print("Time: " + Convert.ToString(result));Параметры и ход выполнения:
- stamp читается один раз, чтобы не смешать разные секунды. Int(stamp/10000) — часы; Int(stamp/100) MOD 100 — минуты; MOD 100 — секунды. Простая строка не дополняет поля нулями.
var stamp = UO.Time();
var hour = stamp / 10000;
var minute = stamp / 100 % 100;
var second = stamp % 100;
UO.Print(Convert.ToString(hour) + ":" + Convert.ToString(minute) + ":" + Convert.ToString(second));Параметры и ход выполнения:
- 180000 — 18:00:00 включительно; 220000 — 22:00:00 не включительно. Одна проверка решает, продолжать ли Main. Расписание не регистрируется, серия автоматически не запускается.
return RunScenario();
object? RunScenario()
{
var stamp = UO.Time();
if (Truth(stamp >= 180000) && Truth(stamp < 220000))
{
UO.Print("Evening batch permitted by local schedule");
}
else
{
UO.Print("Outside the local schedule");
return null;
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- ClockInWindow(stamp,first,last) принимает допустимые HHMMSS. 230000..20000 означает от 23:00 включительно до 02:00 не включительно: OR учитывает полночь. Равные границы означают пустой интервал. В тихий период Main завершается; функция приведена целиком.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
if (Truth(ClockInWindow(UO.Time(), 230000, 20000)))
{
UO.Print("Local quiet period; do not start a new batch");
return null;
}
UO.Print("Outside the local quiet period");
return null;
}
dynamic ClockInWindow(dynamic stamp, dynamic first, dynamic last)
{
if (Truth(first == last))
{
return false;
}
if (Truth(first < last))
{
return Truth(stamp >= first) && Truth(stamp < last);
}
return Truth(stamp >= first) || Truth(stamp < last);
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: int / Integer.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public int Time()
{
var now = timeSource.Now;
return now.Hour * 10000 + now.Minute * 100 + now.Second;
}Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Timer();Читает время работы текущего runtime в десятых долях секунды. Подходит для собственных задержек и отметок действий.
Параметров нет.
int 0..2147483647; единица — 100 мс. При 399 мс вернётся 3. Это показание часов, а не true/false и не остаток перезарядки.
- Параметров нет, форм с аргументами нет. Пустые скобки только читают время: вызов не ждёт, не запускает таймер и не отправляет пакеты в игру.
- Начало отсчёта принадлежит этому экземпляру runtime. Новая запущенная процедура может получить новые часы; нельзя сравнивать значения разных запусков или сохранять их как абсолютную дату. Во время UO.Wait и паузы скрипта реальное время продолжает идти.
- Дробная часть десятых отбрасывается. Примерно через 2485.5 суток число достигает 2147483647 и остаётся таким, не переполняясь.
- Это ваша задержка, а не серверная перезарядка навыка/заклинания и не подтверждение успеха. Команда не позволяет обходить ограничения сервера на движение, заклинания или скрипты.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Timer();
UO.Print("Timer: " + Convert.ToString(result));Параметры и ход выполнения:
- WaitAsync(250) запрашивает 250 мс; фактическая задержка может быть больше. Разность двух отметок делится на 10.0 для получения секунд. Шаг показаний UO.Timer — 100 мс.
var started = UO.Timer();
await Delay(250);
var elapsed = UO.Timer() - started;
var seconds = elapsed / 10.0;
UO.Print("Elapsed seconds: " + Convert.ToString(seconds));
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));Параметры и ход выполнения:
- Предел 30 задан в единицах этой функции. UO.Wait(50) освобождает выполнение между проверками. UO.Targeting читает наличие прицела; пример не кастует и не выбирает цель. Если прицел не появился, цикл заканчивается.
- Дополнительная проверка верхней границы завершает ожидание даже при остановившемся на пределе int счётчике. Статус прицела читается повторно и может измениться между чтениями.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var started = UO.Timer();
while (Truth(UO.Timer() - started < 30) && !(Truth(UO.Targeting())))
{
if (Truth(UO.Timer() >= 2147483647))
{
break;
}
await Delay(50);
}
if (Truth(UO.Targeting()))
{
UO.Print("Target cursor available");
}
else
{
UO.Print("Target wait ended");
}
return null;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- IntervalPassed(started,current,interval) полностью определена под Main. interval=5 — половина секунды в единицах этих часов. Отрицательный интервал, обратный ход и int на верхней границе дают false; точное достижение интервала даёт true.
- Это ваша задержка, а не серверная перезарядка навыка/заклинания и не подтверждение успеха. Команда не позволяет обходить ограничения сервера на движение, заклинания или скрипты.
return await new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenarioAsync();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
async public Task<object?> RunScenarioAsync()
{
var started = UO.Timer();
await Delay(500);
var ready = IntervalPassed(started, UO.Timer(), 5);
if (Truth(ready))
{
UO.Print("Local retry interval passed");
}
return null;
}
dynamic IntervalPassed(dynamic started, dynamic current, dynamic interval)
{
if (Truth(interval < 0) || Truth(current < started))
{
return false;
}
if (Truth(current >= 2147483647))
{
return false;
}
return current - started >= interval;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: int / Integer.
При вызове:
Внутренний код реализации, не самостоятельный скрипт.
public int Timer() => (int)Math.Max(0d, Math.Min(int.MaxValue, timeSource.SinceStart.TotalMilliseconds / 100d));Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
void UO.Wait(object? waitTimeMS);Приостанавливает текущий скрипт на заданное число миллисекунд. Полезно между повторными проверками состояния, чтобы скрипт не крутил непрерывный цикл.
-
waitTimeMS— Целое время в миллисекундах: 1000 = одна секунда. Используйте 0..2147483647. Это не число шагов, не секунды и не таймаут подтверждения сервера.
void — результата нет. Вызывайте отдельной строкой. Окончание задержки не означает, что предмет переместился, заклинание завершилось или соединение установлено: нужное состояние проверяйте отдельно.
- Ноль не создаёт реальной задержки и не подходит как пауза в быстром цикле. Отрицательное время не означает бесконечность: UO.Wait сводит его к 0; UO.Wait/sleep могут отклонить его при активных callback, а в клиентском мосте без них оно не ждёт. Для переносимого скрипта используйте только неотрицательное время.
UO.Wait(100);
// For an asynchronous script, use the host helper:
await WaitAsync(100);Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Команда вызывается отдельной строкой. Сообщение перед ней показывает начало вызова, а не подтверждение действия сервера.
UO.Print("Calling UO.Wait");
UO.Wait(250);Параметры и ход выполнения:
- 250 — четверть секунды. Следующая строка выполняется после ожидания; сообщение Delay complete — текст примера, а не возвращённый результат.
UO.Wait(250);
UO.Print("Delay complete");Параметры и ход выполнения:
- WaitForOnline полностью объявлена в этом скрипте. Аргумент 20 означает максимум двадцать пауз по 250 мс. Соединение проверяется перед паузами и ещё раз после последней. Помощник возвращает состояние Connected (1/0); сама команда ожидания ничего не возвращает и не подключается к серверу.
return RunScenario();
object? RunScenario()
{
return WaitForOnline(20);
return null;
}
dynamic WaitForOnline(dynamic checks)
{
while (Truth(checks > 0))
{
if (Truth(UO.Connected()))
{
return 1;
}
UO.Wait(250);
checks = checks - 1;
}
return UO.Connected();
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Цикл делает ровно три чтения веса. Между чтениями есть две паузы по 500 мс, после последнего паузы нет. Сообщение печатается при первом чтении и при изменении веса. Переменная previous хранит сравниваемое значение, а не настраивает игровой вес.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var previous = -1;
var checks = 0;
while (Truth(checks < 3))
{
var weight = UO.Weight();
if (Truth(weight != previous))
{
UO.Print("Weight: " + Convert.ToString(weight));
previous = weight;
}
checks = checks + 1;
if (Truth(checks < 3))
{
UO.Wait(500);
}
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: waitTimeMS (Any)
Результат: void / Unit.
При вызове:
-
ClassicUO.CSharp.CSharpScriptGlobals.WaitAsync. -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
InjectionScript.Runtime.InjectionApiUO.WaitWithEvents:WaitWithEvents(Arg(0)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Arg:Arg(0).
Внутренний код реализации, не самостоятельный скрипт.
public async Task WaitAsync(int milliseconds)
{
ArgumentOutOfRangeException.ThrowIfNegative(milliseconds);
Checkpoint();
// Short slices allow Pause to suspend further script progress promptly.
int remaining = milliseconds;
while (remaining > 0)
{
int slice = Math.Min(remaining, 25);
await Task.Delay(slice, Cancellation).ConfigureAwait(false);
Checkpoint(); remaining -= slice;
}
}Внутренний код реализации, не самостоятельный скрипт.
case "wait": WaitWithEvents(Arg(0)); return InjectionValue.Unit;Українська · Русский · English · Deutsch · Français · Italiano · Español · 繁體中文 · 日本語 · 한국어
int UO.Waiting();Проверяет, остались ли подготовленные ответы в очереди target.
Параметров нет.
int 1 — есть неотменённая отложенная цель объекта, тайла или отмена следующего прицела; 0 — очередь пуста. Это не наличие открытого курсора; для курсора используйте TargetPresent/Targeting.
Результат команды — числовой флаг: 1 означает выполненное условие, 0 — невыполненное. После var result = команда(...) проверяйте if (result != 0) или if (result == 0). Сохраните результат одного вызова: повторный вызов может выполнить действие снова либо прочитать уже изменившееся состояние.
- Читается очередь всего клиента. Если одновременно работают несколько процедур, учитываются ответы каждой из них.
- Ноль означает только отсутствие ожидающего ответа. Он не подтверждает успешное применение навыка или заклинания на сервере.
Каждый пример можно сохранить отдельным файлом .csx и запускать в IDE. Объект UO и функции ожидания предоставляет host текущей игровой сессии. Демонстрационные serial, имена, координаты и адреса замените своими.
Выполните этот код как отдельный файл .csx. Аргументы видны прямо в вызове; демонстрационные имена, serial и адреса замените своими.
Результат одного вызова выводится в журнал. Число не преобразуется в bool; для массива показано количество элементов.
var result = UO.Waiting();
UO.Print("Waiting: " + Convert.ToString(result));Параметры и ход выполнения:
- После WaitTargetSelf и до серверного target ожидается 1.
- CancelWaitTarget убирает очередь; следующая проверка даст 0.
UO.WaitTargetSelf();
UO.Print(Convert.ToString(UO.Waiting()));
UO.CancelWaitTarget();Параметры и ход выполнения:
- Параметров у проверки нет. UO.Wait=50 мс, максимум 20 ожиданий.
- При оставшемся ответе он отменяется. Проверку результата серверного действия добавляйте отдельно.
return await RunScenarioAsync();
async Task<object?> RunScenarioAsync()
{
var attempts = 0;
while (Truth(UO.Waiting()) && Truth(attempts < 20))
{
await Delay(50);
attempts = attempts + 1;
}
if (Truth(UO.Waiting()))
{
UO.CancelWaitTarget();
}
return null;
}
Task Delay(object? milliseconds) => WaitAsync(checked((int)Convert.ToDouble(milliseconds)));
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;Параметры и ход выполнения:
- Первая строка показывает отложенные ответы, вторая — состояние прицела.
- Возможна очередь без курсора и курсор без очереди; эти значения не взаимозаменяемы.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
UO.Print("Queued: " + Convert.ToString(UO.Waiting()));
UO.Print("Cursor: " + Convert.ToString(UO.TargetPresent()));
return null;
}
}C# учитывает регистр. Используйте точное имя UO. Числовые флаги сравнивайте с 0; bool используйте только там, где сигнатура возвращает bool.
Параметры: Параметров нет.
Результат: int / Integer.
При вызове:
-
InjectionScript.Runtime.InjectionApiUO.Waiting. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.GetWaitTargetQueue:bridge.GetWaitTargetQueue().
Внутренний код реализации, не самостоятельный скрипт.
public int Waiting() => bridge.GetWaitTargetQueue().Length > 0 ? 1 : 0;ClassicUO — Bad Newbie & C# Scripts IDE