Publishers describe a service that receives and processes events generated server-side by various Hiro systems, such as achievements, economy, teams, and more. They act as listeners that respond to events, enabling developers to implement workflows like custom analytics tracking, custom rewards, or integrating with external services.
Publishers can receive events in batches as they are generated by Hiro systems.
Each Publisher may choose to process or ignore each event as it sees fit.
Publishers don’t accumulate (i.e. buffer) events.
Publisher implementations must safely handle concurrent calls and manage any errors or retries internally, as callers will not repeat calls in case of errors.
The Rewards system is a powerful feature that enables you to reward players in-game with currencies, energies, and other items. However, there are specific situations where Publishers can complement the Rewards system by enabling options that aren’t directly supported, such as updating player stats when certain events occur.
Here’s an example of using a Publisher to grant experience points when achievements are claimed:
func(c*ExpRewardPublisher)Send(ctxcontext.Context,loggerruntime.Logger,nkruntime.NakamaModule,userIDstring,events[]*hiro.PublisherEvent){for_,event:=rangeevents{// Only process achievement claim events
ifevent.Name=="achievementClaimed"{// Find the achievement to check if it should reward exp.
// Errors not shown but remember to implement proper error handling in production
achievements,repeatedAchievements,err:=c.systems.GetAchievementsSystem().GetAchievements(ctx,logger,nk,userID)// Look for the achievement in both regular and repeated collections
achievement,ok:=FindAchievement(event.SourceId,achievements,repeatedAchievements)// Check if this achievement is configured to reward exp via AdditionalProperties
// This approach allows us to define exp rewards without modifying the Rewards system
expStr,ok:=achievement.AdditionalProperties["reward_exp"]ifok{// Award the experience points by updating the player's exp stat
exp,err:=strconv.ParseInt(expStr,10,64)// Update the player's exp stat through the Stats system
privateStats:=[]*hiro.StatUpdate{{Name:"exp",Value:exp,Operator:hiro.StatUpdateOperator_STAT_UPDATE_OPERATOR_DELTA,}}}}}}
The Publisher interface defines two methods that must be implemented:
1
2
3
4
5
6
7
8
9
10
typePublisherinterface{// Authenticate is called every time a user authenticates with Hiro.
// The 'created' flag is true if this is a newly created user account.
Authenticate(ctxcontext.Context,loggerruntime.Logger,nkruntime.NakamaModule,userIDstring,createdbool)// Send is called when there are one or more events generated.
Send(ctxcontext.Context,loggerruntime.Logger,nkruntime.NakamaModule,userIDstring,events[]*PublisherEvent)}
The PublisherEvent structure contains information about an event:
1
2
3
4
5
6
7
8
9
10
typePublisherEventstruct{Namestring// Event name
Idstring// Unique event identifier
Timestampint64// Unix timestamp
Metadatamap[string]string// Additional event data
Valuestring// Event value
SystemSystem// The Hiro system that generated this event
SourceIdstring// Identifier of the event source
Sourceany// Configuration of the event source
}