Skip to content

API UO SetEvent

Codex edited this page Sep 22, 2026 · 5 revisions

UO.SetEvent

ClassicUO / Basic IDE

Оглавление · Все команды · Scripts & Runtime

Включает или выключает наблюдение за изменениями состояния персонажа и позволяет выбрать одноразовую либо повторяющуюся реакцию. Например, можно один раз отменить оставшийся target после смерти или получать предупреждения о низкой выносливости. Обработчик задаётся отдельно от условия; основной скрипт должен продолжать выполнять UO.Wait.

Точный синтаксис

UO.SetEvent(name:Any, stateValue:Any) -> Unit
UO.SetEvent(name:Any, stateValue:Any, repeatOrHandler:Any) -> Unit
UO.SetEvent(nameValue:Any, stateValue:Any, repeatValue:Any, subNameValue:Any) -> Unit

Выберите одну из зарегистрированных форм. Параметры передаются позиционно. Any означает значение BASIC с преобразованием внутри команды; Unit — отсутствие возвращаемого значения.

Параметры

  • name — Строка с одним из пяти имён: ChangeHitPoints, ChangeMana, ChangeStamina, Death, SeeNewPlayer. Регистр не важен; допустим префикс ev, например evChangeMana. Пробелы по краям удаляются. Числового каталога событий нет; произвольное имя не создаёт новое событие.
  • nameValue — То же имя события, что name; это название первого параметра в форме с четырьмя аргументами, не дополнительное значение.
  • stateValue — True/1 включает наблюдение, False/0 снимает подписку. Передавайте логические значения без кавычек. При числовом преобразовании любое ненулевое целое включает наблюдение. Отключение не ждёт и не останавливает уже запущенный обработчик.
  • repeatOrHandler — Третий аргумент имеет два назначения. Нечисловая непустая строка, например "OnManaChanged", задаёт обработчик с автоматическим повторением. Число/Boolean задаёт только повтор: False/0 — одно срабатывание, True/1 — повторять; обработчик в этой форме не назначается. Строка "1" тоже числовая и не является именем процедуры. Для одноразового обработчика используйте четыре аргумента.
  • repeatValue — В форме с четырьмя аргументами: False/0 — удалить подписку после первого обнаруженного перехода, True/1 — оставить её для следующих изменений. Одноразовая подписка снимается и тогда, когда обработчик не найден либо менеджер отклонил его запуск; не путайте обнаружение события с успешным завершением процедуры.
  • subNameValue — Строка — имя загруженной доступной процедуры SUB без обязательных аргументов, например "OnHealthChanged". Передаётся имя, а не вызов со скобками. Пустая/пробельная строка при stateValue=True включает наблюдение БЕЗ обработчика. Для отключения передайте stateValue=False. Допустимые совместимые префиксы "exec " и "_exec " удаляются; предпочтительнее простое имя. Процедура должна присутствовать в загруженном скрипте, не быть Private и успешно проходить проверку.

Возвращает

Unit — значения нет. Вызывайте отдельной строкой, без VAR result = и без сравнения с True/1. Завершение регистрации не подтверждает, что обработчик найден, запущен или что сервер совершил действие. Если имя процедуры не найдено при событии, вызов не происходит.

Поведение

  • Два аргумента: False отключает событие; True включает повторяющееся наблюдение без обработчика. Никакая процедура с совпадающим именем автоматически не подставляется. Эта форма не возвращает обнаруженный факт и не заменяет проверку HP/Mana/Dead.
  • Три аргумента: непустая строка, не распознаваемая как целое число, трактуется как имя процедуры и включает повторение; числовое значение/Boolean задаёт repeat без обработчика. Для ясного рабочего сценария передавайте имя SUB либо используйте все четыре аргумента.
  • Четыре аргумента явно задают имя события, включение, повторение и обработчик. Оба логических параметра пишутся без кавычек. FALSE/0 = one-shot: подписка снимается после первого обнаруженного перехода, а не после окончания обработчика.
  • Повторная регистрация одного события заменяет его прежние настройки и запоминает текущее состояние как новую точку отсчёта. Подписки SetEvent и SetEventProc на одно нормализованное имя внутри одного скрипта используют одну запись, не накапливаются.
  • ChangeHitPoints сравнивает текущее HP self с предыдущим снимком; срабатывает и при потере, и при восстановлении здоровья. ChangeMana и ChangeStamina аналогично реагируют в обе стороны. Это не только урон, расход маны или усталость.
  • Death срабатывает при переходе живой → мёртвый. Регистрация уже мёртвого персонажа не вызывает обработчик сразу; повторная смерть после воскрешения может вызвать его снова.
  • SeeNewPlayer сравнивает набор загруженных mobiles, исключая 0 и self. Название не означает проверку реального игрока: сюда входят NPC и существа. Один или несколько новых serial за одну проверку вызывают одну попытку запуска. Возврат ушедшего из загруженного набора mobile также может считаться новым появлением. ID не передаётся обработчику — нужные объекты надо найти отдельно.
  • UO.Wait делит ожидание на интервалы до 25 мс и после каждого проверяет события; Wait(0) тоже выполняет проверку. Это опрос доступного состояния, а не перехват каждого сетевого пакета: быстрое изменение и возврат между проверками может быть пропущено. В вычислительном цикле без UO.Wait или после завершения Main постоянного наблюдения нет.
  • Обработчик запускается через менеджер процедур, отдельно от ожидающего Main. Не рассчитывайте на его синхронное завершение или общий локальный VAR. Повторный запуск уже работающей процедуры и настройка запрета наложения процедур могут блокировать запуск. Держите обработчики короткими; при включённом запрете параллельных процедур проверяйте состояние прямо в основном цикле.
  • Подписка относится к экземпляру выполняющегося скрипта. Снимайте её в Main, который её создал: одноимённая команда внутри отдельно запущенного обработчика изменит его собственные подписки. Отмена регистрации не останавливает уже запущенный обработчик. Используйте TRY/FINALLY для обычного выхода или обрабатываемой ошибки; принудительная остановка также прекращает дальнейший опрос этого скрипта.
  • Неизвестное непустое имя события при регистрации отклоняется с системным сообщением. Пустое имя ничего не делает. Наличие обработчика проверяется только при срабатывании; ошибку в его имени лучше обнаружить заранее через SubExists и проверку скрипта в IDE.

Внутренние функции: последовательность выполнения

Ниже описана реализация этого движка. Имена внутренних методов не являются дополнительными командами BASIC.

1. SetEvent

Нормализует имена и сохраняет начальный снимок состояния через CaptureLegacyEventSnapshot.

Неподдерживаемое событие не остаётся активным; новый обработчик заменяет прежний для этого имени.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция SetEvent.

2. CaptureLegacyEventSnapshot

Читает HP, mana, stamina, dead и загруженные mobiles, исключая self и 0.

Создаёт начальные значения для обнаружения последующих изменений.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция CaptureLegacyEventSnapshot.

3. WaitWithEvents

Разбивает ожидание на интервалы до 25 мс. После каждого вызывает DispatchLegacyEvents; нулевое ожидание также выполняет проверку.

Скрипт даёт клиенту возможность обновить состояние и обработать отмену.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция WaitWithEvents.

4. DispatchLegacyEvents

Сравнивает новый снимок с предыдущим. Для группы новых mobiles хватает одного нового serial. Обновляет снимок и проверяет наличие процедуры.

При обнаруженном изменении вызывает bridge.Exec(handler). Параметры события не передаются; повторяющаяся подписка остаётся.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция DispatchLegacyEvents.

5. Exec

Находит загруженную процедуру и передаёт её менеджеру.

Если процедура не найдена, запуск не происходит.

Исходник проекта: src/ClassicUO.Client/Game/Managers/ClassicUOInjectionApiBridge.cs; функция Exec.

6. RunProcedure

Проверяет доступность, параметры, отмену и ограничения одновременных запусков.

Запуск асинхронный; Unit не является подтверждением завершения обработчика.

Исходник проекта: src/ClassicUO.Client/Game/Managers/YokoInjectionManager.cs; функция RunProcedure.

Формы с двумя и тремя аргументами приводятся к SetEvent(name, state, repeat, handler). Примеры ниже содержат все обработчики и отключают подписки при выходе.

Примеры

Пример 1. Один раз отменить незавершённый target после смерти

SUB OnFirstDeath()
    # Обработчик запускается отдельно и не получает аргументов.
    IF UO.Targeting() THEN
        UO.CancelTarget()
        UO.Print("Death detected: active targeting cancelled")
    ELSE
        UO.Print("Death detected: no active target")
    END IF
END SUB

SUB Main()
    # Trueвключить; Falseтолько первое изменение живой -> мёртвый.
    UO.SetEvent("Death", True, False, "OnFirstDeath")
    TRY
        UO.Wait(8000)
    FINALLY
        # Полезно и если смерти не было: не оставляем подписку активной.
        UO.SetEvent("Death", False)
    END TRY
END SUB

Разбор параметров и выполнения:

  • Наблюдение длится восемь секунд. Death уже мёртвого персонажа не вызывает обработчик немедленно. Второе событие смерти после воскрешения в этом примере уже не обрабатывается.
  • Обработчик проверяет активный курсор цели в момент выполнения и только тогда вызывает CancelTarget. Подготовленная очередь без активного курсора в этом примере не отменяется. Скрипт не воскрешает персонажа, не останавливает все скрипты и не завершает Main. Не запускайте пример, если хотите сохранить активную цель.

Пример 2. Повторяющееся предупреждение о выносливости: короткая форма

SUB OnFatigue()
    # Событие означает любое изменение, а IF выбирает низкое значение.
    VAR staminaNow = UO.Stamina()
    IF staminaNow < 10 THEN
        UO.Print("Stamina is " + CStr(staminaNow) + ": consider resting")
    END IF
END SUB

SUB Main()
    # Строка в третьем аргументе задаёт SUB; повторение включено.
    UO.SetEvent("evChangeStamina", True, "OnFatigue")
    TRY
        FOR tick = 1 TO 24
            UO.Wait(250)
        NEXT
    FINALLY
        # evChangeStamina и ChangeStaminaодно нормализованное имя.
        UO.SetEvent("ChangeStamina", False)
    END TRY
END SUB

Разбор параметров и выполнения:

  • 24 × 250 мс — шесть секунд. 10 — наш порог в обработчике, не дополнительный аргумент SetEvent. Рост выносливости также вызывает обработчик, но при значении от 10 сообщение не выводится.
  • True, "OnFatigue" отличается от True, True: последний вариант задаёт повторение без процедуры. Скрипт не повышает выносливость и не меняет скорость сервера.

Пример 3. Переключить обработчик маны без накопления подписок

SUB OnManaLog()
    UO.Print("Mana now: " + CStr(UO.Mana()))
END SUB

SUB OnLowMana()
    # Во второй фазе предупреждаем только о низком значении.
    IF UO.Mana() < 20 THEN
        UO.Print("Mana below 20: check the cost before casting")
    END IF
END SUB

SUB Main()
    UO.SetEvent("ChangeMana", True, True, "OnManaLog")
    TRY
        UO.Wait(2000)
        # Заменяем обработчик; OnManaLog больше не запускается.
        UO.SetEvent("ChangeMana", True, True, "OnLowMana")
        UO.Wait(3000)
    FINALLY
        UO.SetEvent("ChangeMana", False)
    END TRY
END SUB

Разбор параметров и выполнения:

  • Первые две секунды каждое обнаруженное изменение вызывает OnManaLog. Следующие три секунды используется OnLowMana. Регистрация второго обработчика сама по себе его не запускает.
  • Замена не прерывает уже запущенную старую процедуру. Эти короткие обработчики не используют локальные переменные Main. При запрете наложения процедур менеджер может отклонить запуск — для такого режима проверяйте Mana прямо в Main.

Clone this wiki locally