Passing context userid from matchloop to other functions

Hi … We’re using GO for our server logic and using matches to essentially create a match per player to handle server-authoritative skilling within the game. From within the MatchLoop, we need to call other functions obviously because we’re not gonna have the whole game logic in the MatchLoop function. When I call the other function from within the MatchLoop, userID, _ := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)) is always blank for some reason. If i run the function (rpc) from nakama console, the function works but not if i call that rpc function from the match loop. Any idea what’s going on? or am I passing it incorrectly? Is the context of the MatchLoop different from the context of the rpc function?

in MatchLoop i’m calling the function like this and all of it works… it’s just for some reason, userID, _ := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string) returns blank.

if opCode == 123 {
canDoAction, _ = StartPlayerAction(ctx, logger, db, nk, string(message.GetData()))
}

func StartPlayerAction(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { }

If this is the not the correct way, how would you suggest to call other functions from within in the MatchLoop and pass more data to it?

Hello @S3cZ0mbie. Could you describe the environment you’re running the code in? What’s the version of Nakama? Are you using the RPC function just for the sake of modularization?

The environment is Ubuntu running the latest Nakama version and yes, using RPC functions for the sake of modularization. I’m also initializing the funcs using this in main.go

func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, initializer runtime.Initializer) error {

}

I’m really not sure how to pass the data between the matchloop and the func back and forth (because dispatcher.BroadcastMessage isn’t found from within the func either)

Hi.

I think I understand better the situation. The data passing should happen as in any function however, in the case you presented it doesn’t make sense for the context ctx to contain a user id in the match loop. There is no user session on that computation, thus no id is injected into the context.

So if you need to refactor the desired function in such a way that can be invoked from multiple locations but in each the data comes from different sources.

Hmmm i see… Essentially use a different method to initialize functions instead of main.go and handle each independently? At the moment I’m assigining the return from rpc functions to variables in the matchloop and to use the userID from within the functions I’m setting a global variable but I strongly think this is gonna cause problems as soon as more people are logged in. If you have any example, tutorial or anything that we can use as an example how we should be properly passing data between matchloops and rpc functions and back, I would greatly appreciate it. Thanks so much for taking the time to answer.

@S3cZ0mbie I think it’s important to first clarify why you want to communicate and/or share state between RPC functions and match loop invocations. Can you provide more information here?

Matches are designed to be initialised with external data (matchmaker output, RPC function payloads etc) but once they are running interaction is expected via the match handler functions. Users send data to a match they’ve joined, and receive data directly from the match. RPC functions should not be in the picture here.

Hello :slight_smile: Well we are using external functions that are being called from matchloop because we can’t possibly have all the game logic within the matchloop and have one enormous matchloop file. At least in other languages, when it comes to modularity, you have separate functions that are called. As I said in my original post, I’m not really a golang dev but I kinda assumed since having separate functions is how it works in most languages, it is the same in golang.

Essentially the game is a server authoritative rpg, where you skill, collect items etc. To avoid cheating, the way you skill is that the client sends to nakama “hey I wanna fish here…nakama checks if you can and every x amount of seconds, gives you xp and sends a broadcast to the client to reflect that xp”. However the checking if the user is able to do that action in the requested area, has to happen on the server. If all the game code has to be inside the matchloop, we’re gonna end up with a massive file which will be hard to maintain rather than splitting it into separate functions in separate files.

Hope that sheds some more light on the usecase.

Thanks for taking the time and replying.

@S3cZ0mbie You can divide up your code on match-loop however you like; but the point is for the code and data it manages to be built and used in the context of a match handler, not RPCs.

The common pattern is:

  1. check message type (movement, action, etc)
  2. hand off to appropriate function (regular Go code)
  3. go to next message

This is a project template that might help you: nakama-project-template/match_handler.go at master · heroiclabs/nakama-project-template · GitHub

Yeah we’ve been using that project to help us figure things out but it’s rather a simplistic example with the whole game in the matchloop and doesn’t pass data around other functions which doesn’t help my specific question, but thanks for answering.

@S3cZ0mbie You shouldn’t be calling custom RPCs from the match handler as there’s no need to - just create standard Go functions like func doSomething(userID UUID, ...){} and pass around whatever data you need.

I see…ok will try that and see how it goes. Thank you very much for clarifying.