# Does Match Handler functions are called when a match is created from client side?

**URL:** <https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221>\
**Category:** Runtime Framework\
**Tags:** server-framework, typescript\
**Created:** [November 1, 2022, 9:41am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221 "2022-11-01T09:41:02Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 9:41am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/1 "2022-11-01T09:41:02Z")

</div>

I have set up Typescript Runtime Server using this [video](https://youtu.be/FXguREV6Zf8). As per this video everything is okay. My question is, Does the [Match Handler](https://youtu.be/FXguREV6Zf8) functions are called when a match is created from client side.

**main.ts**

```auto
let InitModule: nkruntime.InitModule = function (
  ctx: nkruntime.Context,
  logger: nkruntime.Logger,
  nk: nkruntime.Nakama,
  initializer: nkruntime.Initializer
) {
  const matchInit = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    params: { [key: string]: string }
  ): { state: nkruntime.MatchState; tickRate: number; label: string } {
    logger.debug("Lobby match created");
    return {
      state: { presences: {}, emptyTicks: 0 },
      tickRate: 1, // 1 tick per second = 1 MatchLoop func invocations per second
      label: "",
    };
  };

  const matchJoin = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presences: nkruntime.Presence[]
  ): { state: nkruntime.MatchState } | null {
    presences.forEach(function (p) {
      state.presences[p.sessionId] = p;
    });
    logger.debug("Lobby match joined");
    return {
      state,
    };
  };

  const matchLeave = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presences: nkruntime.Presence[]
  ): { state: nkruntime.MatchState } | null {
    presences.forEach(function (p) {
      delete state.presences[p.sessionId];
    });

    return {
      state,
    };
  };

  const matchLoop = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    messages: nkruntime.MatchMessage[]
  ): { state: nkruntime.MatchState } | null {
    // If we have no presences in the match according to the match state, increment the empty ticks count
    if (state.presences.length === 0) {
      state.emptyTicks++;
    }

    // If the match has been empty for more than 100 ticks, end the match by returning null
    if (state.emptyTicks > 100) {
      return null;
    }

    return {
      state,
    };
  };
  const matchJoinAttempt = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presence: nkruntime.Presence,
    metadata: { [key: string]: any }
  ): {
    state: nkruntime.MatchState;
    accept: boolean;
    rejectMessage?: string | undefined;
  } | null {
    logger.debug("%q attempted to join Lobby match", ctx.userId);

    return {
      state,
      accept: true,
    };
  };
  const matchSignal = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    data: string
  ): { state: nkruntime.MatchState; data?: string } | null {
    logger.debug("Lobby match signal received: " + data);

    return {
      state,
      data: "Lobby match signal received: " + data,
    };
  };
  const matchTerminate = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    graceSeconds: number
  ): { state: nkruntime.MatchState } | null {
    logger.debug("Lobby match terminated");

    return {
      state,
    };
  };
  initializer.registerMatch("lobby", {
    matchInit,
    matchJoinAttempt,
    matchJoin,
    matchLeave,
    matchLoop,
    matchSignal,
    matchTerminate,
  });
};

// Reference InitModule to avoid it getting removed on build
// !InitModule && InitModule.bind(null);

```

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [November 1, 2022, 11:02am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/2 "2022-11-01T11:02:00Z")

</div>

Hi @Shahariar_Ashik,

In order to make use of your server authoritative match handler you should create the match on the server side.

You could initiate this from the client by having it call an RPC (and then having the server create the match and pass back the match ID to the client) or have the client use the matchmaker and configure a hook on the server to create the match that way.

You can see examples of both of these methods in our [Lobby Guide](https://heroiclabs.com/docs/nakama/guides/concepts/lobby/).

---

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 11:09am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/3 "2022-11-01T11:09:11Z")

</div>

Recently I have registered two RPC’s to check if they works. But only healthcheck RPC is showing in Nakama Console, not the other one. Can you please help?

**main.ts**

```auto
initializer.registerRpc("matchcreate", rpcMatchcreate);
initializer.registerRpc("healthcheck", rpcHealthcheck);

```

**matchcreate.ts**

```auto
function rpcMatchcreate(
  ctx: nkruntime.Context,
  logger: nkruntime.Logger,
  nk: nkruntime.Nakama,
  payload: string
) {
  logger.info("match create rpc called");
  return JSON.stringify({ succeed: true });
}

```

**healthcheck.ts**

```auto
function rpcHealthcheck(
  ctx: nkruntime.Context,
  logger: nkruntime.Logger,
  nk: nkruntime.Nakama,
  payload: string
) {
  logger.info("healthcheck rpc called");
  return JSON.stringify({ succeed: true });
}

```

tsconfig.json

```auto
{
  "files": ["./main.ts", "./matchcreate.ts", "./healthcheck.ts"],
  "compilerOptions": {
    "target": "es5",
    "typeRoots": ["./node_modules"],
    "outFile": "./build/index.js",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

```

This RPC functions are for just checking. If this works, then I will add the code of creating match by the server in creatematch.ts file.

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [November 1, 2022, 11:12am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/4 "2022-11-01T11:12:48Z")

</div>

Are you running Nakama via docker or locally as a binary executable?

Please check that the generated JavaScript file contains the code for your `rpcMatchcreate` function as expected. If you’re running via Docker it can sometimes be useful to force it to rebuild your image by running:

```auto
docker compose up --build nakama

```

---

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 11:13am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/5 "2022-11-01T11:13:30Z")

</div>

via Docker exactly as the video I attached.

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [November 1, 2022, 11:15am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/6 "2022-11-01T11:15:00Z")

</div>

Ok thanks for clarifying. Then please check that the bundled JavaScript inside the docker container is as you expect (i.e. registers the match create rpc and contains the function).

---

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 11:35am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/7 "2022-11-01T11:35:37Z")

</div>

Now after forcefully building the image it is now showing. Can you please do one more help?

```auto
let module = 'some.folder.module';
let params = {
  some: 'data',
}

let matchId: string;

try {
  matchId = nk.matchCreate(module, params);
} catch(error) {
  // Handle error
}

```

I wrote this code in **matchcreate.ts** but not working. Actually I am confused about the module=“” this option. As I am running Typescript Runtime server how should be the actual code look like?

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [November 1, 2022, 11:49am UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/8 "2022-11-01T11:49:40Z")

</div>

The `module` parameter should be the same string that you used when registering the match handler with `registerMatch`.

Using the lobby guide as an example you can see where we first [Register the match handler](https://heroiclabs.com/docs/nakama/guides/concepts/lobby/#registering-the-match-handler) and then subsequently [Create a match via an RPC](https://heroiclabs.com/docs/nakama/guides/concepts/lobby/#creating-privatepublic-matches) using the same module name.

---

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 12:10pm UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/9 "2022-11-01T12:10:55Z")

</div>

Yes, I got it now. module should be equals “lobby” in my case. But now I am getting different error.  
From Nakam Console:

```auto
Error whilst making RPC call: Unknown Error

```

From logs:

```auto
typescript-project-nakama-1 | {"level":"info","ts":"2022-11-01T11:55:32.153Z","caller":"server/runtime_javascript_logger.go:74","msg":"match create rpc called","rpc_id":"matchcreate"}
typescript-project-nakama-1 | {"level":"fatal","ts":"2022-11-01T11:55:32.163Z","caller":"server/runtime_javascript_match_core.go:103","msg":"Failed to get JavaScript match loop function reference.","mid":"7ba2caf7-356c-4180-b925-7a2e789299e4","fn":"matchInit","key":"matchInit"}

```

main.ts file

```auto
let InitModule: nkruntime.InitModule = function (
  ctx: nkruntime.Context,
  logger: nkruntime.Logger,
  nk: nkruntime.Nakama,
  initializer: nkruntime.Initializer
) {
  initializer.registerRpc("matchcreate", rpcMatchcreate);
  initializer.registerRpc("healthcheck", rpcHealthcheck);

  const matchInit = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    params: { [key: string]: string }
  ): { state: nkruntime.MatchState; tickRate: number; label: string } {
    logger.debug("Lobby match created");
    return {
      state: { presences: {}, emptyTicks: 0 },
      tickRate: 1, // 1 tick per second = 1 MatchLoop func invocations per second
      label: "",
    };
  };

  const matchJoin = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presences: nkruntime.Presence[]
  ): { state: nkruntime.MatchState } | null {
    presences.forEach(function (p) {
      state.presences[p.sessionId] = p;
    });
    logger.debug("Lobby match joined");
    return {
      state,
    };
  };

  const matchLeave = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presences: nkruntime.Presence[]
  ): { state: nkruntime.MatchState } | null {
    presences.forEach(function (p) {
      delete state.presences[p.sessionId];
    });

    return {
      state,
    };
  };

  const matchLoop = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    messages: nkruntime.MatchMessage[]
  ): { state: nkruntime.MatchState } | null {
    // If we have no presences in the match according to the match state, increment the empty ticks count
    if (state.presences.length === 0) {
      state.emptyTicks++;
    }

    // If the match has been empty for more than 100 ticks, end the match by returning null
    if (state.emptyTicks > 100) {
      return null;
    }

    return {
      state,
    };
  };
  const matchJoinAttempt = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    presence: nkruntime.Presence,
    metadata: { [key: string]: any }
  ): {
    state: nkruntime.MatchState;
    accept: boolean;
    rejectMessage?: string | undefined;
  } | null {
    logger.debug("%q attempted to join Lobby match", ctx.userId);

    return {
      state,
      accept: true,
    };
  };
  const matchSignal = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    data: string
  ): { state: nkruntime.MatchState; data?: string } | null {
    logger.debug("Lobby match signal received: " + data);

    return {
      state,
      data: "Lobby match signal received: " + data,
    };
  };
  const matchTerminate = function (
    ctx: nkruntime.Context,
    logger: nkruntime.Logger,
    nk: nkruntime.Nakama,
    dispatcher: nkruntime.MatchDispatcher,
    tick: number,
    state: nkruntime.MatchState,
    graceSeconds: number
  ): { state: nkruntime.MatchState } | null {
    logger.debug("Lobby match terminated");

    return {
      state,
    };
  };
  initializer.registerMatch("lobby", {
    matchInit,
    matchJoinAttempt,
    matchJoin,
    matchLeave,
    matchLoop,
    matchSignal,
    matchTerminate,
  });
};

// Reference InitModule to avoid it getting removed on build
// !InitModule && InitModule.bind(null);

```

**matchcreate.ts**

```auto
function rpcMatchcreate(
  ctx: nkruntime.Context,
  logger: nkruntime.Logger,
  nk: nkruntime.Nakama,
  payload: string
) {
  logger.info("match create rpc called");
  let module = "lobby";
  let params = {
    some: "data",
  };

  let matchId: string;

  try {
    matchId = nk.matchCreate(module, params);
  } catch (error) {
    // Handle error
    matchId = "";
    logger.info("having error during creating match from server");
  }
  return JSON.stringify({ match_id: matchId });
}

```

---

<div class="post-metadata">

**Author:** ![Shahariar\_Ashik](https://avatars.discourse-cdn.com/v4/letter/s/d78d45/32.png) [@Shahariar\_Ashik](https://forum.heroiclabs.com/u/Shahariar_Ashik)\
**Post date:** [November 1, 2022, 2:41pm UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/10 "2022-11-01T14:41:16Z")

</div>

Update: Worked. I added all the handler functions inside the InitModule in main.ts file that’s why it was not working. Now I threw all of them outside the InitModule. Now it works. Thanks a lot for the help though.

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [November 1, 2022, 3:21pm UTC](https://forum.heroiclabs.com/t/does-match-handler-functions-are-called-when-a-match-is-created-from-client-side/3221/11 "2022-11-01T15:21:22Z")

</div>

Glad to hear you got it working.
