Channel State
Overviewβ
Channel state allows you to store and manage custom data within channels, similar to player state. This feature enables implementing complex multiplayer mechanics such as:
- Clans with shared banks - shared resources management
- Tournaments with prize pools - collective prize distribution
- Raids and boss battles - shared health pools and progress tracking
- Guild systems - collective achievements and resources
- Collaborative events - shared objectives and rewards
Channel state is perfect for implementing collaborative gameplay mechanics where multiple players need to share and modify the same data
Channel Fields Configurationβ
When creating or editing a channel template, you can configure custom fields before the restrictions group:
Field Typesβ
Field Type | Description | Use Cases |
---|---|---|
String | Text values | Player names, descriptions, status messages |
Boolean | True/false values | Feature toggles, completion flags |
Number | Numeric values | Health points, scores, quantities |
Field Settingsβ
Property | Description | Use Cases |
---|---|---|
Enumeration | Predefined options | Difficulty levels, game modes |
Min-Max | Numeric values with limits | Health pools, resource caps |
Access Controlβ
For field access, you can configure access permissions for different user roles:
- Owner - Channel creator/administrator
- Member - Regular channel participants
- Guest - Players who haven't joined the channel
Available Permissionsβ
- Allow setting channel variables - Can modify field values
- Allow adding to channel variables - Can increment numeric values
- Allow subtracting from channel variables - Can decrement numeric values
SDK Methodsβ
Fetching Channel Stateβ
const channel = await gp.channels.fetchChannel({ id: 123 });
channel.state; // All channel values
// Example
console.log(channel.state.gold);
channel.fields; // All channel field definitions
Setting Valuesβ
const { success, value } = await gp.channels.setValue({
channelId: 123,
key: 'gold',
value: 123,
});
Adding Valuesβ
const { success, value } = await gp.channels.addValue({
channelId: 123,
key: 'gold',
value: 100,
});
Event Subscriptionsβ
// Subscribe to value changes
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
console.log(`Channel ${channelId}: ${key} changed to ${value}`);
});
// Subscribe to successful operations
gp.channels.on('setValue', ({ channelId, key, value }) => {
console.log(`Successfully set ${key} to ${value} in channel ${channelId}`);
});
// Subscribe to failed operations
gp.channels.on('error:setValue', ({ channelId, key, value }) => {
console.log(`Failed to set ${key} to ${value} in channel ${channelId}`);
});
Server-Side Validationβ
When values are changed on the server, GamePush does the following:
- Access validation - Check user permissions
- Min/Max limits - Enforce field constraints if enabled
- Value updates - Apply the changes
- Event broadcasting - Send
changeValue
event to all channel members - Size limits - IMPORTANT! field values are limited to 64KB
Implementation Examplesβ
1. Clan with Shared Bankβ
Create a clan channel with a shared bank system where members can contribute gold and only the owner can withdraw.
Channel Template Setupβ
- Create a channel template for clans
- Add a Number field named
bank
- Set permissions:
- Members: Allow adding to channel variables
- Owner: Allow subtracting from channel variables
Implementationβ
// Player contributes 100 gold to clan bank
const contributeGold = async (amount) => {
// Add to clan bank
await gp.channels.addValue({
channelId: clanChannelId,
key: 'bank',
value: amount,
});
// Subtract from player's gold
await gp.player.set('gold', -amount);
};
// Owner withdraws gold from clan bank
const withdrawGold = async (amount) => {
// Subtract from clan bank
await gp.channels.addValue({
channelId: clanChannelId,
key: 'bank',
value: -amount,
});
// Add to owner's gold
await gp.player.set('gold', amount);
};
// Listen for bank changes
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
if (key === 'bank') {
updateBankDisplay(value);
}
});
2. Tournament with Prize Poolβ
Create tournaments where players contribute entry fees and winners share the prize pool.
Channel Template Setupβ
- Create a tournament channel template
- Add a Number field named
prizeAmount
- Set permissions:
- Members and Owner: Allow adding to channel variables
Implementationβ
// Player joins tournament (pays entry fee)
const joinTournament = async () => {
const entryFee = 100;
// Add to prize pool
await gp.channels.addValue({
channelId: tournamentChannelId,
key: "prizeAmount",
value: entryFee
});
// Subtract entry fee from player
await gp.player.set('gold', -entryFee);
};
// Tournament ends - distribute prizes to top 5 players
const distributePrizes = async (winners) => {
const channel = await gp.channels.fetchChannel({ id: tournamentChannelId });
const totalPrize = channel.state.prizeAmount;
const prizePerWinner = totalPrize / winners.length;
// Work through logic to understand that player won a prize
const isMyPlayerInTop = true;
// Award prize
for (isMyPlayerInTop) {
await gp.player.set('gold', prizePerWinner);
}
// Leave the channel
gp.channels.leave({ channelId: tournamentChannelId });
};
// Listen for prize pool updates
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
if (key === 'prizeAmount') {
updatePrizeDisplay(value);
}
});
3. Raid Boss Battleβ
Create raid channels where players fight a boss with shared health pool.
Channel Template Setupβ
- Create a raid channel template for 5 players
- Add Number fields:
hp
- Current boss healthmaxHp
- Maximum boss health
- Set permissions:
- Members and Owner: Allow subtracting from channel variables (for damage)
Implementationβ
// Get raid channel
const channel = await gp.channels.fetchChannel({ id: raidChannelId });
// Update boss HP value
gp.channels.on('event:changeValue', ({ channelId, key, value }) => {
// Only for our channel
if (channel.id !== channelId) {
return;
}
// Keep state up to date
channel.state[key] = value;
if (key === 'hp') {
updateBossHealthDisplay(value);
}
});
// Player attacks boss
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;
// Notify about boss damage in chat (optional)
await gp.channels.sendMessage({
channelId: raidChannelId,
text: `${gp.player.name} deals ${damage} damage! HP: ${currentHp}/${maxHp}`,
});
// Check if boss is defeated
if (currentHp <= 0) {
await defeatBoss();
}
}
};
// Boss defeated
const defeatBoss = async () => {
// If owner - notify everyone about raid completion
if (channel.ownerId === gp.player.id) {
await gp.channels.sendMessage({
channelId: raidChannelId,
text: 'π Boss defeated! Rewards distributed!',
});
}
// Give reward to player
const reward = 1000;
await gp.player.set('gold', reward);
// Leave the channel
await gp.channels.leave({ channelId: raidChannelId });
};
Best Practicesβ
- Design field permissions carefully - Ensure only authorized users can modify critical values
- Use min/max constraints - Prevent unrealistic values (e.g., negative health)
- Implement proper error handling - Check operation success before proceeding
- Monitor channel events - Use event listeners to update UI and game state
- Consider data size - Keep field values under 64KB limit
- Test thoroughly - Verify permissions and constraints work as expected
Channel state is a powerful feature that opens up many possibilities for collaborative gameplay. Start with simple implementations and gradually add complexity as needed.
Error Handlingβ
When working with channel state, you may encounter various errors. Below is a list of possible errors and their meanings:
Error Code | Description |
---|---|
fields_not_found | Channel template fields are not configured or not found |
channel_not_found | The specified channel does not exist or has been deleted |
value_not_number | Attempted to perform numeric operations on a non-numeric field |
channel_state_not_found | Channel state data is not available or corrupted |
key_not_found | The specified field key does not exist in the channel |
internal_error | Server-side error occurred during the operation |
value_already_max | Attempted to increase a value that is already at maximum limit |
value_already_min | Attempted to decrease a value that is already at minimum limit |
value_too_low | The provided value is below the minimum allowed limit |
value_too_high | The provided value is above the maximum allowed limit |
value_too_large | The provided value exceeds the 64KB size limit |
invalid_field_type | The operation is not compatible with the field type |
Basic Errorsβ
These errors are common across all channel operations:
Error Code | Description |
---|---|
player_not_found | The player making the request is not found |
project_not_found | The game project is not found or inactive |
origin_not_allowed | The request origin is not allowed for this project |
player_banned | The player is banned and cannot perform this action |
internal_error | An unexpected server error occurred |