Hooks are a feature of the Nakama server runtime that allow you to run custom server code before or after certain server events happen. This can be useful in a number of scenarios, some of which are given below as examples.
All registration calls below are to be run inside the InitModule function.
For more information on hooks and how they can be used see the hooks documentation.
These hooks run before a particular server runtime event occurs. This can be used to modify the input to a particular function or take additional actions before it occurs.
This hook checks that a group name does not contain profanity before allowing it to be created. Note that profanity checking functionality is not provided by Nakama.
Server
1
2
3
4
5
6
7
8
9
10
initializer.registerBeforeCreateGroup(beforeCreateGroup);letbeforeCreateGroup : nkruntime.BeforeHookFunction<nkruntime.CreateGroupRequest>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,data: nkruntime.CreateGroupRequest):nkruntime.CreateGroupRequest{// Check the group name does not contain profanity (containsProfanity implementation not provided)
if(containsProfanity(data.name)){thrownewError("Profanity detected.")}returndata;};
This hook denies an attempt to delete a group that still contains more than 1 user.
Server
1
2
3
4
5
6
7
8
9
10
11
initializer.registerBeforeDeleteGroup(beforeDeleteGroup);letbeforeDeleteGroup : nkruntime.BeforeHookFunction<nkruntime.DeleteGroupRequest>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,data: nkruntime.DeleteGroupRequest):nkruntime.DeleteGroupRequest{// Deny the delete request if the group still has more than one user
constresult=nk.groupUsersList(data.groupId,null,null,null);if(result.groupUsers.length>1){thrownewError("Group still has users.")}returndata;};
Server
1
2
3
4
5
6
7
8
9
10
11
12
initializer.RegisterBeforeDeleteGroup(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*api.DeleteGroupRequest)(*api.DeleteGroupRequest,error){groupUsers,_,err:=nk.GroupUsersList(ctx,in.GroupId,100,nil,"")iferr!=nil{returnnil,runtime.NewError("error retrieving group users",13)}iflen(groupUsers)>1{returnnil,runtime.NewError("group still has users",9)}returnin,nil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook sends a notification to each user that has been added as a friend by another user, letting them know that they have received a friend request.
Server
1
2
3
4
5
6
7
8
initializer.registerAfterAddFriends(afterAddFriends);letafterAddFriends: nkruntime.AfterHookFunction<void,nkruntime.AddFriendsRequest>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,data: void,request: nkruntime.AddFriendsRequest){// Notify each user that they have received a friend request
request.ids.forEach(function(id){nk.notificationSend(id,'Friend Request Received',{message:`You have received a friend request from ${ctx.username}.`},1,null,true);});};
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
initializer.RegisterAfterAddFriends(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*api.AddFriendsRequest)error{username,ok:=ctx.Value(runtime.RUNTIME_CTX_USERNAME).(string)if!ok{returnruntime.NewError("error getting username",13)}for_,friendId:=rangein.Ids{content:=map[string]interface{}{"message":fmt.Sprintf("You have received a friend request from %s",username),}nk.NotificationSend(ctx,friendId,"Friend Request Received",content,1,nil,true)}returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook sends a message to a group notifying the group users that a particular user has left.
Server
1
2
3
4
5
6
7
initializer.registerAfterLeaveGroup(afterLeaveGroup);letafterLeaveGroup: nkruntime.AfterHookFunction<void,nkruntime.LeaveGroupRequest>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,data: void,request: nkruntime.LeaveGroupRequest){// Send a message to the group to say the player left
constchannelId=nk.channelIdBuild(null,request.groupId,nkruntime.ChanType.Group);nk.channelMessageSend(channelId,{message:`${ctx.username} left the group.`},null,null,true);};
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
initializer.RegisterAfterLeaveGroup(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*api.LeaveGroupRequest)error{username,ok:=ctx.Value(runtime.RUNTIME_CTX_USERNAME).(string)if!ok{returnruntime.NewError("error getting username",13)}channelId,err:=nk.ChannelIdBuild(ctx,nil,in.GroupId,runtime.Group)iferr!=nil{returnruntime.NewError("error getting channel id",13)}content:=map[string]interface{}{"message":fmt.Sprintf("%s left the group.",username),}nk.ChannelMessageSend(ctx,channelId,content,nil,nil,true)returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook rewards a player with 10 coins (in their virtual wallet whenever they authenticate by device ID.
Server
1
2
3
4
5
6
initializer.registerAfterAuthenticateDevice(afterAuthenticateDevice);letafterAuthenticateDevice: nkruntime.AfterHookFunction<nkruntime.Session,nkruntime.AuthenticateDeviceRequest>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,data: nkruntime.Session,request: nkruntime.AuthenticateDeviceRequest){// Give the player 10 coins for logging in
nk.walletUpdate(ctx.userId,{coins: 10},null,true);};
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
initializer.RegisterAfterAuthenticateDevice(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,out*api.Session,in*api.AuthenticateDeviceRequest)error{// Give the player 10 coins for logging in
userId,ok:=ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)if!ok{returnruntime.NewError("error getting userId",13)}changeset:=map[string]int64{"coins":10,}nk.WalletUpdate(ctx,userId,changeset,nil,true)returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook rewards the top 3 scoring players in a leaderboard with 1,000 coins whenever the leaderboard resets.
Server
1
2
3
4
5
6
7
8
9
10
initializer.registerLeaderboardReset(onLeaderboardReset);letonLeaderboardReset : nkruntime.LeaderboardResetFunction=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,leaderboard: nkruntime.Leaderboard,reset: number){// Reward top 3 players with 1,000 coins and send them a notification telling them what their rank was
consttopRecords=nk.leaderboardRecordsList(leaderboard.id,null,3,null,null);topRecords.records.forEach(function(record){nk.walletUpdate(record.ownerId,{coins: 1000},null,true);nk.notificationSend(record.ownerId,'Congratulations',{message:`Well done, you ranked ${record.rank}!`},2,null,true);});};
initializer.RegisterLeaderboardReset(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,leaderboard*api.Leaderboard,resetint64)error{// Reward top 3 players with 1,000 coins and send them a notification telling them what their rank was
topRecords,_,_,_,err:=nk.LeaderboardRecordsList(ctx,leaderboard.Id,nil,3,"",0)iferr!=nil{returnruntime.NewError("error getting leaderboard records",13)}for_,record:=rangetopRecords{changeset:=map[string]int64{"coins":1000,}content:=map[string]interface{}{"message":fmt.Sprintf("Well done, you ranked %d!",record.Rank),}nk.WalletUpdate(ctx,record.OwnerId,changeset,nil,true)nk.NotificationSend(ctx,record.OwnerId,"Congratulations",content,2,"",true)}returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
initializer.registerTournamentEnd(onTournamentEnd);letonTournamentEnd : nkruntime.TournamentEndFunction=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,tournament: nkruntime.Tournament,end: number,reset: number){// Reward tournament leader with 10,000 coins and a rare item
consttopRecord=nk.tournamentRecordsList(tournament.id,null,1,null,null);constwinnerId=topRecord.records[0].ownerId;// Give the player 10,000 coins
nk.walletUpdate(winnerId,{coins: 10000},null,true);// Get the player's existing inventory
conststorageRead : nkruntime.StorageReadRequest={collection:"inventory",key: winnerId,userId: winnerId};constresult=nk.storageRead([storageRead]);letinventory={};if(result.length>0){inventory=result[0].value;}// Add the rare item or increase quantity
if(!inventory["rare-sword"]){inventory["rare-sword"]=1;}else{inventory["rare-sword"]++;}// Write the updated inventory to the storage engine
conststorageWrite : nkruntime.StorageWriteRequest={collection:"inventory",key: winnerId,userId: winnerId,permissionWrite: 0,permissionRead: 1,value: inventory}nk.storageWrite([storageWrite]);};
initializer.RegisterTournamentEnd(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,tournament*api.Tournament,end,resetint64)error{// Reward tournament leader with 10,000 coins and a rare item
topRecord,_,_,_,err:=nk.TournamentRecordsList(ctx,tournament.Id,nil,1,"",0)iferr!=nil{returnruntime.NewError("error getting tournament records",13)}winnerId:=topRecord[0].OwnerId// Give the player 10,000 coins
changeset:=map[string]int64{"coins":10000,}nk.WalletUpdate(ctx,winnerId,changeset,nil,true)// Get the player's existing inventory
storageRead:=&runtime.StorageRead{Collection:"inventory",Key:winnerId,UserID:winnerId,}result,err:=nk.StorageRead(ctx,[]*runtime.StorageRead{storageRead})iferr!=nil{returnruntime.NewError("error reading player inventory",13)}varinventorymap[string]intiflen(result)>0{iferr:=json.Unmarshal([]byte(result[0].Value),&inventory);err!=nil{logger.Error("error unmarshaling inventory",err)returnruntime.NewError("error unmarshaling inventory",13)}}else{inventory=make(map[string]int)}// Add the rare item or increase quantity
if_,ok:=inventory["rare-sword"];!ok{inventory["rare-sword"]=1}else{inventory["rare-sword"]+=1}// Write the updated inventory to the storage engine
inventoryJson,err:=json.Marshal(inventory)iferr!=nil{returnruntime.NewError("error marshaling inventory",13)}storageWrite:=&runtime.StorageWrite{Collection:"inventory",Key:winnerId,UserID:winnerId,PermissionWrite:0,PermissionRead:1,Value:string(inventoryJson),}_,err=nk.StorageWrite(ctx,[]*runtime.StorageWrite{storageWrite})iferr!=nil{returnruntime.NewError("error writing inventory",13)}returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook checks to see if a user is trying to join a Direct Message channel for a non-friend. If so, it blocks their request to join the channel.
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
initializer.registerRtBefore("ChannelJoin",beforeChannelJoin);letbeforeChannelJoin : nkruntime.RtBeforeHookFunction<nkruntime.EnvelopeChannelJoin>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,envelope: nkruntime.EnvelopeChannelJoin):nkruntime.EnvelopeChannelJoin|void{// If the channel join is a DirectMessage type, check to see if the user is friends with the recipient first
if(envelope.channelJoin.type==nkruntime.ChanType.DirectMessage){constresult=nk.friendsList(ctx.userId,null,0,null);constfiltered=result.friends.filter(function(friend){returnfriend.user.userId==envelope.channelJoin.target;});if(filtered.length==0){thrownewError("You cannot direct message someone you are not friends with.");}}returnenvelope;};
initializer.RegisterBeforeRt("ChannelJoin",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*rtapi.Envelope)(*rtapi.Envelope,error){envelope,ok:=in.Message.(*rtapi.Envelope_ChannelJoin)if!ok{returnnil,runtime.NewError("error getting envelope as ChannelJoin envelope",13)}userId,ok:=ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)if!ok{returnnil,runtime.NewError("error getting userId",13)}// If the channel join is a DirectMessage type, check to see if the user is friends with the recipient first
ifenvelope.ChannelJoin.Type==2{state:=0friends,_,err:=nk.FriendsList(ctx,userId,100,&state,"")iferr!=nil{returnnil,runtime.NewError("error getting friends list",13)}isFriends:=falsefor_,friend:=rangefriends{iffriend.User.Id==envelope.ChannelJoin.Target{isFriends=truebreak}}if!isFriends{returnnil,runtime.NewError("you cannot direct message someone you are not friends with.",9)}}returnin,nil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.
This hook lets a recipient know that the other user has left the channel after that user has left.
Server
1
2
3
4
5
6
initializer.registerRtAfter("ChannelLeave",afterChannelLeave);letafterChannelLeave : nkruntime.RtAfterHookFunction<nkruntime.EnvelopeChannelLeave>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,output: nkruntime.EnvelopeChannelLeave|null,input: nkruntime.EnvelopeChannelLeave){// Send a message to the channel after leaving, notifying others that the user left
nk.channelMessageSend(input.channelLeave.channelId,{message:`${ctx.userId} left the channel.`},"","",true);};
initializer.RegisterAfterRt("ChannelLeave",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,out,in*rtapi.Envelope)error{envelope,ok:=in.Message.(*rtapi.Envelope_ChannelLeave)if!ok{returnruntime.NewError("error getting envelope as ChannelLeave envelope",13)}userId,ok:=ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)if!ok{returnruntime.NewError("error getting userId",13)}// Send a message to the channel after leaving, notifying others that the user left
content:=map[string]interface{}{"message":fmt.Sprintf("%s left the channel.",userId),}nk.ChannelMessageSend(ctx,envelope.ChannelLeave.ChannelId,content,"","",true)returnnil})
Code snippet for this language Lua has not been found. Please choose another language to show equivalent examples.