Agency Docs
QBESXStandalone

Agency-Watch Кастомные Приложения

Теперь с AgencyOS27: бесплатное обновление для всех, у кого часы уже есть.

v27.0.0Бесплатно7 Страницы

⌚ Своё приложение для Agency-Watch

Часы открыты. Владелец сервера может добавить приложение, которое выглядит и работает как встроенное, на тех же компонентах, с теми же цветами и теми же переводами.

Условие: версия Pro. Собственные приложения существуют, только если на сервере работает Agency-Phone и он есть у игрока. Без Pro они регистрируются, но никогда не доставляются: интерфейс о них не узнаёт, в App Store их нет, а сервер отклоняет каждое действие, которое они отправляют. Это проверяется в трёх разных местах и не отключается.

ФайлОбязателенЧто делает
apps/<id>/app.luaдаРегистрирует приложение: название, иконка, цвет, категория.
apps/<id>/app.jsдаЭкран: что он рисует и как реагирует.
apps/<id>/app.cssнетСобственные стили. Загружаются, только если задано style = true.
apps/<id>/server.luaнетСерверная логика, которую может вызывать ваше приложение.

Папка называется точно так же, как id приложения. Так часы находят app.js и app.css, не записывая путь дважды, а дважды записанные пути рано или поздно расходятся.

Всё, что лежит в apps/, внесено в escrow_ignore: оно остаётся читаемым и редактируемым на вашем диске, и обновление часов его никогда не перезаписывает.

1 Регистрация приложения

apps/hello/app.lua

AgencyWatchApp({
    id       = 'hello',          -- lowercase, digits and _, must match the folder
    name     = 'Hello',
    icon     = 'raster',         -- one of the built-in icons, see below
    color    = '#5ac8fa',        -- #rrggbb
    category = 'tools',          -- tools | games | driving | style | connected
    style    = true,             -- also load app.css
    texts    = { en = 'Hello', de = 'Hallo' },   -- optional, name per language
})

Приложение с неверным id, без названия, с неизвестной категорией или с цветом не в формате #rrggbb отклоняется в консоли сервера, явно и с указанием причины. Наполовину зарегистрированных не бывает: такая ошибка иначе проявилась бы только тогда, когда игрок нажмёт на приложение.

После добавления файлов выполните refresh и restart Agency-Watch. При запуске часы сообщают, что зарегистрировалось.

2 Отрисовка экрана

apps/hello/app.js

AgencyWatch.app('hello', {

    render: function (w) {            // required, returns HTML
        var d = w.data();
        return w.card('Hello, ' + w.esc(d.name)) +
               w.section('Steps') +
               w.row({ icon: 'schritte', static: true,
                       top: String(d.steps || 0) }) +
               w.button('Roll a die', ' data-roll');
    },

    bind: function (w) {              // optional, runs right after
        w.click('[data-roll]', function () {
            w.toServer('roll', { sides: 6 }).then(function (a) {
                if (a.ok) w.notify('Hello', 'You rolled ' + a.data.value);
            });
        });
    },
});

render выполняется при каждом построении экрана, поэтому не хранит состояние между вызовами. Всё, что должно пережить перерисовку, храните в переменной вне объекта приложения.

Обе функции работают внутри страховки. Если ваш код выбросит ошибку, приложение покажет строку с ошибкой, а часы продолжат работать; сама ошибка уйдёт в консоль F8.

3 Набор инструментов

В w есть всё, что нужно приложению на часах, и ничего сверх этого. Интерфейс, который умеет всё, уже никогда нельзя изменить, поэтому этот намеренно небольшой.

ВызовЧто вы получаете
w.data()Плоский снимок: time, hour, minute, date, weekday, name, job, health, armour, pulse, steps, distance, calories, speed, heading, weather, pro.
w.row({icon, top, bottom, end, attrs, static})Строка списка в стиле часов.
w.section(text)Заголовок раздела.
w.card(html)Поверхность.
w.button(text, attrs)Кнопка. В attrs передаётся строка атрибутов как есть, например ' data-roll'.
w.toggle(on)Переключатель вкл./выкл.
w.center(html)По центру, для одного крупного значения.
w.icon(name)Одна из встроенных иконок.
w.esc(text)Экранирует текст. Используйте для всего, что пришло не от вас.
w.text(key, fallback)Перевод из часов.
w.click(selector, fn)Вешает обработчик. Только внутри bind.
w.notify(title, text, icon, colour)Уведомление на часах.
w.refresh()Перерисовка без анимации появления.
w.close()Назад, как стрелка в заголовке.
w.toServer(action, data)Запрос к серверу. Возвращает promise.
w.id, w.versionid вашего приложения и версия AgencyOS.

Снимок является копией, а не ссылкой. В часах хранятся ещё контакты, сообщения и данные карт; ничего из этого туда не попадает.

4 Серверная часть

apps/hello/server.lua

AgencyWatchAction('hello', 'roll', function(src, data)
    local sides = tonumber(data and data.sides) or 6
    if sides < 2 then sides = 2 end
    if sides > 100 then sides = 100 end
    return { value = math.random(1, math.floor(sides)) }
end)

w.toServer всегда завершается: { ok: true, data: … } или { ok: false, reason: '…' }, даже если сервер так и не ответил. Приложение никогда не зависнет в ожидании, а причина всегда лежит на верхнем уровне, какая бы сторона ни отказала.

reasonЗначение
no_proНет версии Pro. Без неё собственных приложений не существует.
unknownНет такого приложения или такое действие не зарегистрировано.
too_fastОграничение частоты: не больше десяти запросов за пять секунд на игрока.
errorВаш обработчик выбросил ошибку. Подробности в консоли сервера.
timeoutНет ответа в течение двенадцати секунд.
dataЗапрос не был таблицей.

Всё, что приходит в data, пришло от клиента и является пожеланием, а не фактом. Проверяйте каждое значение перед использованием. Всё, что имеет значение (деньги, предметы, результаты), должно решаться на сервере и больше нигде.

5 Стили

Цвета часов доступны как CSS-переменные и следуют тому, что владелец выбрал в Studio. С жёстко заданными цветами приложение останется синим на зелёных часах.

var(--text)   var(--text-2)   var(--leise)
var(--akzent) var(--gruen)    var(--rot)    var(--gelb)
var(--karte)  var(--karte-hoch)   var(--linie)
var(--grund)

Добавляйте префикс к своим классам. Экран общий для всех приложений, и у класса с именем .large быстро найдутся соседи.

6 Встроенные иконки

Любую из них можно передать в icon в app.lua или в w.icon():

akku auto blitz brief einkauf farben flugzeug gewitter glocke haken helligkeit herz hoch hupe karte karte-pin kein-signal kino kompass kreuz krone lampe laufen lautlos links loeschen minus mobil mond nebel neuladen pause personen pin plus qr raster rechts regen regler runter sanduhr schild schloss schloss-auf schnee schritte signal sonne sp-fall sp-flug sp-ring sp-turm sprechen stoppuhr telefon telefon-aus tempo ton uhr verboten wiedergabe wlan wolke zahnrad

Названия иконок намеренно остаются как есть. Это id, а не подписи: игрок их никогда не читает, а переименованный id ломает все приложения, которые уже его используют.

📦 С часами поставляется рабочий пример

apps/example/ внутри ресурса представляет собой полноценное рабочее приложение: компоненты, вызов сервера, уведомление и собственный CSS. Скопируйте папку, переименуйте её, и у вас готова рабочая отправная точка.

Краткая версия этой страницы лежит рядом, в apps/README.md.

После этой страницы всё ещё не получается? Дальше подключается наша поддержка.