Skip to content

События

WebGUI имеет двунаправленную систему именованных событий между сервером и страницей — прямой аналог системы событий WebView в alt:V.

Сервер → страница

Java API

java
// Отправить событие на страницу конкретного игрока
WebviewApi.emitToPage(player, "walletUpdate", "{\"balance\":1500}");

// Строка — тоже валидный JSON
WebviewApi.emitToPage(player, "serverRestart", "\"5 минут\"");

// Без данных
WebviewApi.emitToPage(player, "sessionExpired", null);

Второй аргумент — имя события. Третий — любое валидное JSON-значение: объект, массив, строка, число, boolean или null.

Получение на странице — React-хук

tsx
import { useWebGUIEvent } from '@webgui/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

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>').

Отписка

js
function onWalletUpdate(data) { ... }

window.webgui.on('walletUpdate', onWalletUpdate)
// позже:
window.webgui.off('walletUpdate', onWalletUpdate)

В React хук useWebGUIEvent очищает подписку автоматически при анмаунте компонента.


Страница → сервер

Отправка со страницы

Используйте window.webgui.postToGame с любым каналом, кроме встроенных (log, close):

js
window.webgui.postToGame({ channel: 'shop:buy', itemId: 'minecraft:diamond', qty: 1 })

Или через React-хук:

tsx
const post = usePostToGame()

post({ channel: 'shop:buy', itemId: 'minecraft:diamond', qty: 1 })

Полный JSON-пейлоад (включая поле channel) пересылается на сервер как C2S-пакет.

Получение на сервере — Java API

java
// Регистрируется один раз, например при инициализации мода
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:

java
WebviewServerEvents.PAGE_EVENT.register((player, channel, payload) -> {
    if (!channel.equals("shop:buy")) return;
    // разобрать payload...
});

Встроенные каналы (только клиент, до сервера не доходят)

КаналДействие
logЛогирует сообщение в клиентский лог игры
closeЗакрывает активный GUI или HUD-оверлей

Пример полного round-trip

Сервер — открываем магазин и пушим данные инвентаря:

java
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-компонент:

tsx
import { useWebGUIEvent, usePostToGame } from '@webgui/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>
      ))}
    </>
  )
}