События
WebGUI имеет двунаправленную систему именованных событий между сервером и страницей — прямой аналог системы событий WebView в alt:V.
Сервер → страница
Java API
// Отправить событие на страницу конкретного игрока
WebviewApi.emitToPage(player, "walletUpdate", "{\"balance\":1500}");
// Строка — тоже валидный JSON
WebviewApi.emitToPage(player, "serverRestart", "\"5 минут\"");
// Без данных
WebviewApi.emitToPage(player, "sessionExpired", null);Второй аргумент — имя события. Третий — любое валидное JSON-значение: объект, массив, строка, число, boolean или null.
Получение на странице — React-хук
import { useWebGUIEvent } from '@webgui/client/react'
interface WalletUpdate { balance: number }
export function Wallet() {
const [balance, setBalance] = useState(0)
useWebGUIEvent<WalletUpdate>('walletUpdate', ({ balance }) => {
setBalance(balance)
})
return <p>Баланс: {balance}</p>
}Получение на странице — vanilla JS
// Через window.webgui.on (инжектится модом)
window.webgui.on('walletUpdate', (data) => {
console.log('баланс:', data.balance)
})
// Или напрямую через DOM-событие
window.addEventListener('webgui:walletUpdate', (e) => {
console.log('баланс:', e.detail.balance)
})window.webgui.on и window.addEventListener слушают одно и то же CustomEvent('webgui:<eventName>').
Отписка
function onWalletUpdate(data) { ... }
window.webgui.on('walletUpdate', onWalletUpdate)
// позже:
window.webgui.off('walletUpdate', onWalletUpdate)В React хук useWebGUIEvent очищает подписку автоматически при анмаунте компонента.
Страница → сервер
Отправка со страницы
Используйте window.webgui.postToGame с любым каналом, кроме встроенных (log, close):
window.webgui.postToGame({ channel: 'shop:buy', itemId: 'minecraft:diamond', qty: 1 })Или через React-хук:
const post = usePostToGame()
post({ channel: 'shop:buy', itemId: 'minecraft:diamond', qty: 1 })Полный JSON-пейлоад (включая поле channel) пересылается на сервер как C2S-пакет.
Получение на сервере — Java API
// Регистрируется один раз, например при инициализации мода
WebviewApi.onPageEvent("shop:buy", (player, rawJson) -> {
JsonObject obj = JsonParser.parseString(rawJson).getAsJsonObject();
String item = obj.get("itemId").getAsString();
int qty = obj.get("qty").getAsInt();
giveItem(player, item, qty);
});Получение на сервере — Fabric-событие
Для модов, предпочитающих Fabric event bus:
WebviewServerEvents.PAGE_EVENT.register((player, channel, payload) -> {
if (!channel.equals("shop:buy")) return;
// разобрать payload...
});Встроенные каналы (только клиент, до сервера не доходят)
| Канал | Действие |
|---|---|
log | Логирует сообщение в клиентский лог игры |
close | Закрывает активный GUI или HUD-оверлей |
webgui:death
Приходит на страницу смерти, когда игрок умирает — если сервер задал deathScreenUrl.
window.addEventListener('webgui:death', (e) => {
const { killer, cause, deathMessage, hardcore, canRespawn } = e.detail;
document.querySelector('#msg').textContent = deathMessage;
document.querySelector('#by').textContent =
killer.type === 'environment' ? 'мир' : killer.name;
document.querySelector('#respawn').hidden = !canRespawn;
});| Поле | Тип | Описание |
|---|---|---|
killer.type | "player" | "mob" | "environment" | Кто убил. environment — падение, утопление, огонь, всё без сущности за этим. |
killer.name | string | null | Отображаемое имя: ник игрока или имя моба ("Zombie" либо кастомное). Для environment — null. |
killer.uuid | string | null | UUID убийцы. Для environment — null. |
killer.entityType | string | Registry-id вида minecraft:zombie. Только для мобов — у игрока тип и так "player". |
cause | string | Ванильный id типа урона: mob, player, fall, lava, … |
deathMessage | string | Сообщение о смерти, которое показала бы ваниль, например "Steve was slain by Zombie". |
hardcore | bool | Хардкорный ли мир. |
canRespawn | bool | На хардкоре false — кнопку возрождения показывать не нужно, она не сработает. |
Возрождение — window.webgui.respawn(); это замена ванильной кнопки Respawn и единственный способ уйти со страницы.
Пример полного round-trip
Сервер — открываем магазин и пушим данные инвентаря:
WebviewApi.openGui(player, "https://your-site.example.com/shop");
WebviewApi.emitToPage(player, "inventoryLoad", buildInventoryJson(player));
WebviewApi.onPageEvent("shop:buy", (player, rawJson) -> {
processShopPurchase(player, rawJson);
// возвращаем обновлённый баланс на страницу
WebviewApi.emitToPage(player, "walletUpdate", "{\"balance\":" + getBalance(player) + "}");
});Страница — React-компонент:
import { useWebGUIEvent, usePostToGame } from '@webgui/client/react'
export function ShopScreen() {
const [items, setItems] = useState([])
const [balance, setBalance] = useState(0)
const post = usePostToGame()
useWebGUIEvent('inventoryLoad', setItems)
useWebGUIEvent<{ balance: number }>('walletUpdate', ({ balance }) => setBalance(balance))
function buy(itemId: string) {
post({ channel: 'shop:buy', itemId, qty: 1 })
}
return (
<>
<p>Баланс: {balance}</p>
{items.map(item => (
<button key={item.id} onClick={() => buy(item.id)}>{item.name}</button>
))}
</>
)
}