Состояние канала
Обзор
Состояние канала позволяет хранить и управлять пользовательскими данными внутри каналов, аналогично состоянию игрока. Эта функция позволяет реализовать сложные многопользовательские механики, такие как:
- Кланы с общим банком - управление общими ресурсами
- Турниры с призовыми фондами - коллективное распределение призов
- Рейды и битвы с боссами - общие пулы здоровья и отслеживание прогресса
- Системы гильдий - коллективные достижения и ресурсы
- Совместные события - общие цели и награды
Состояние канала идеально подходит для реализации совместных игровых механик, где несколько игроков должны делиться и изменять одни и те же данные
Настройка полей канала
При создании или редактировании шаблона канала вы можете настроить пользовательские поля перед группой с ограничениями:
Типы полей
Тип поля | Описание | Случаи использования |
---|---|---|
Строковые | Текстовые значения | Имена игроков, описания, статусные сообщения |
Булевые | Значения true/false | Переключатели функций, флаги завершения |
Числовые | Числовые значения | Очки здоровья, счет, количества |
Настройки полей
Свойство | Описание | Случаи использования |
---|---|---|
Перечисляемые | Предопределенные варианты | Уровни сложности, игровые режимы |
Мин-макс | Числовые значения с ограничениями | Пулы здоровья, лимиты ресурсов |
Контроль доступа
Для доступа к полям вы можете настроить права доступа для разных ролей пользователей:
- Владелец - Создатель/администратор канала
- Участник - Обычные участники канала
- Гость - Игроки не вступившие в канал
Доступные разрешения
- Разрешить устанавливать переменные канала - Может изменять значения полей
- Разрешить добавлять значение к переменным канала - Может увеличивать числовые значения
- Разрешить вычитать значение из переменных канала - Может уменьшать числовые значения
Методы SDK
Получение состояния канала
const channel = await gp.channels.fetchChannel({ id: 123 });
channel.state; // Все значения канала
// Пример
console.log(channel.state.gold);
channel.fields; // Все определения полей канала
Установка значений
const { success, value } = await gp.channels.setValue({
channelId: 123,
key: 'gold',
value: 123,
});
Добавление значений
const { success, value } = await gp.channels.addValue({
channelId: 123,
key: 'gold',
value: 100,
});
Подписка на события
// Подписка на изменения значений
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
console.log(`Канал ${channelId}: ${key} изменился на ${value}`);
});
// Подписка на успешные операции
gp.channels.on('setValue', ({ channelId, key, value }) => {
console.log(`Успешно установлено ${key} в ${value} в канале ${channelId}`);
});
// Подписка на неудачные операции
gp.channels.on('error:setValue', ({ channelId, key, value }) => {
console.log(`Не удалось установить ${key} в ${value} в канале ${channelId}`);
});
Серверная валидация
При изменении значений на сервере GamePush делает следующее:
- Валидация доступа - Проверка прав пользователя
- Ограничения мин/макс - Применение ограничений полей, если включено
- Обновление значений - Применение изменений
- Рассылка событий - Отправка события
changeValue
всем участникам канала - Ограничения размера - ВАЖНО! значения полей ограничены 64КБ
Примеры реализации
1. Клан с общим банком
Создайте канал клана с системой общего банка, где участники могут вносить золото, а только владелец может снимать.
Настройка шаблона канала
- Создайте шаблон канала для кланов
- Добавьте Числовое поле с именем
bank
- Установите права:
- Участники: Разрешить добавлять значение к переменным канала
- Владелец: Разрешить вычитать значение из переменных канала
Реализация
// Игрок вносит 100 золота в банк клана
const contributeGold = async (amount) => {
// Добавить в банк клана
await gp.channels.addValue({
channelId: clanChannelId,
key: 'bank',
value: amount,
});
// Вычесть из золота игрока
await gp.player.add('gold', -amount);
};
// Владелец снимает золото из банка клана
const withdrawGold = async (amount) => {
// Вычесть из банка клана
await gp.channels.addValue({
channelId: clanChannelId,
key: 'bank',
value: -amount,
});
// Добавить к золоту владельца
await gp.player.add('gold', amount);
};
// Слушать изменения банка
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
if (key === 'bank') {
updateBankDisplay(value);
}
});
2. Турнир с призовым фондом
Создайте турниры, где игроки вносят вступительные взносы, а победители делят призовой фонд.
Настройка шаблона канала
- Создайте шаблон канала турнира
- Добавьте Числовое поле с именем
prizeAmount
- Установите права:
- Участники и Владелец: Разрешить добавлять значение к переменным канала
Реализация
// Игрок присоединяется к турниру (платит вступительный взнос)
const joinTournament = async () => {
const entryFee = 100;
// Добавить в призовой фонд
await gp.channels.addValue({
channelId: tournamentChannelId,
key: "prizeAmount",
value: entryFee
});
// Вычесть вступительный взнос у игрока
await gp.player.add('gold', -entryFee);
};
// Турнир завершен - распределить призы топ-5 игрокам
const distributePrizes = async (winners) => {
const channel = await gp.channels.fetchChannel({ id: tournamentChannelId });
const totalPrize = channel.state.prizeAmount;
const prizePerWinner = totalPrize / winners.length;
// Проработать логику, чтобы понять, что игрок занял призовое место
const isMyPlayerInTop = true;
// Зачесть приз
for (isMyPlayerInTop) {
await gp.player.add('gold', prizePerWinner);
}
// Покидаем канал
gp.channels.leave({ channelId: tournamentChannelId });
};
// Слушать обновления призового фонда
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
if (key === 'prizeAmount') {
updatePrizeDisplay(value);
}
});
3. Рейд с боссом
Создайте каналы рейдов, где игроки сражаются с боссом с общим пулом здоровья.
Настройка шаблона канала
- Создайте шаблон канала рейда для 5 игроков
- Добавьте Числовые поля:
hp
- Текущее здоровье боссаmaxHp
- Максимальное здоровье босса
- Установите права:
- Участники и Владелец: Разрешить вычитать значение из переменных канала (для урона)
Реализация
// Получаем канал рейда
const channel = await gp.channels.fetchChannel({ id: raidChannelId });
// Обновляем значение HP босса
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
// Только для нашего канала
if (channel.id !== channelId) {
return;
}
// Держим состояние актуальным
channel.state[key] = value;
if (key === 'hp') {
updateBossHealthDisplay(value);
}
});
// Игрок атакует босса
const attackBoss = async (damage) => {
const { success, value } = await gp.channels.addValue({
channelId: raidChannelId,
key: 'hp',
value: -damage,
});
if (success) {
const currentHp = channel.state.hp;
const maxHp = channel.state.maxHp;
// Уведомляем о нанесении урона боссу в чат (опционально)
await gp.channels.sendMessage({
channelId: raidChannelId,
text: `${gp.player.name} получает ${damage} урона! HP: ${currentHp}/${maxHp}`,
});
// Проверить, побежден ли босс
if (currentHp <= 0) {
await defeatBoss();
}
}
};
// Босс побежден
const defeatBoss = async () => {
// Если владелец - уведомляем всех о завершении рейда
if (channel.ownerId === gp.player.id) {
await gp.channels.sendMessage({
channelId: raidChannelId,
text: '🎉 Босс побежден! Награды распределены!',
});
}
// Выдаем награду игроку
const reward = 1000;
await gp.player.add('gold', reward);
// Выходим из канала
await gp.channels.leave({ channelId: raidChannelId });
};
Лучшие практики
- Тщательно проектируйте права полей - Убедитесь, что только авторизованные пользователи могут изменять критические значения
- Используйте ограничения мин/макс - Предотвращайте нереалистичные значения (например, отрицательное здоровье)
- Реализуйте правильную обработку ошибок - Проверяйте успешность операции перед продолжением
- Отслеживайте события канала - Используйте слушатели событий для обновления UI и игрового состояния
- Учитывайте размер данных - Держите значения полей в пределах лимита 64КБ
- Тщательно тестируйте - Убедитесь, что права и ограничения работают как ожидается
Состояние канала - это мощная функция, которая открывает множество возможностей для совместной игры. Начните с простых реализаций и постепенно добавляйте сложность по мере необходимости.
Обработка ошибок
При работе с состоянием канала вы можете столкнуться с различными ошибками. Ниже приведен список возможных ошибок и их значений:
Код ошибки | Описание |
---|---|
fields_not_found | Поля шаблона канала не настроены или не найдены |
channel_not_found | Указанный канал не существует или был удален |
value_not_number | Попытка выполнить числовые операции с нечисловым полем |
channel_state_not_found | Данные состояния канала недоступны или повреждены |
key_not_found | Указанный ключ поля не существует в канале |
internal_error | Произошла серверная ошибка во время операции |
value_already_max | Попытка увеличить значение, которое уже на максимальном лимите |
value_already_min | Попытка уменьшить значение, которое уже на минимальном лимите |
value_too_low | Предоставленное значение ниже минимально допустимого лимита |
value_too_high | Предоставленное значение выше максимально допустимого лимита |
value_too_large | Предоставленное значение превышает лимит размера в 64КБ |
invalid_field_type | Операция несовместима с типом поля |
Базовые ошибки
Эти ошибки общие для всех операций с каналами:
Код ошибки | Описание |
---|---|
player_not_found | Игрок, делающий запрос, не найден |
project_not_found | Игровой проект не найден или неактивен |
origin_not_allowed | Источник запроса не разрешен для этого проекта |
player_banned | Игрок заблокирован и не может выполнить это действие |
internal_error | Произошла неожиданная серверная ошибка |