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

⌚ Своё приложение для 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.version | id вашего приложения и версия 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.