Svelte Real-time Multiplayer Game: User Presence
Tags: svelte, javascript, realtime, game
Published: 2023-06-15 14:27:28

---
title: "Svelte Real-time Multiplayer Game: User Presence"
published: "true"
description: "Svelte real-time multiplayer game 👋🏽 see who is online by adding presence or awareness to improve multi-user game 🧑🏽 user experience."
tags: "svelte, javascript, realtime, game"
canonical_url: "https://rodneylab.com/svelte-realtime-multiplayer-game/"
cover_image: "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5tw2z4gok3c1eass490.png"

---

## 🙋🏽 Adding Presence or Awareness to Real-time Apps

We continue our look at the Svelte real-time multiplayer game, this time having a look at **presence**, which is also known as **awareness**.

<a href="https://rodneylab.com/sveltekit-ably/">In an earlier SvelteKit Ably post</a>, we had a first look at creating a real-time, multiplayer online game using Ably to provide serverless WebSockets.  The game is basic; two players take turns to try to claim the most squares on a grid. They claim individual squares by marking each of its four sides with their colour.  Although the game is simple, it makes use of **powerful real-time features** useful for chat and more sophisticated multi-user applications.

In this post, we turn to improving user experience by adding a lobby.  Players enter the lobby when they are ready to play, and from there can invite others to join them in a game, as well as accept challenges from players.

### What are Presence and Awareness?

Presence and awareness are, essentially, the same thing, and allow users or players to advertise their presence on the channel.  This is just what we need for the game; when a player enters the lobby, they want other waiting players to know they are available to play.  Similarly, the player entering wants to know who is online and potentially to invite them to play.  Presence or awareness makes this possible.

There are a few prominent providers of WebSocket services for real-time interactions.  Ably, uses the term presence while **partykit** uses awareness.  Two other providers: **PubNub** and **Pusher** also use the term presence.

Now we know what presence and awareness are, let&rsquo;s see how they got used in the Sqvuably game.

![Svelte Real-time Multiplayer Game: Screen capture shows lobby for game with five players present. For each player, you see their name and an adjacent button for inviting them to play.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hs9lqtdycl3mwx6f4u6k.png)

## 🧱 What we're Building

Similarly to the previous post on the Sqvuably game, we won&rsquo;t build presence from start-to-finish.  Instead, the focus here, is on code snippets which demonstrate the main features and how you can use presence with Ably in Svelte.  The full code for the game is in a Git repo (linked below), which you can clone for further details.

The main new feature is the lobby, which uses presence.  From the lobby, you can invite other users to join you in game and also, accept invitations from other players.  Players will automatically leave the lobby when they start their new game.

## 🛋️ Lobby Client Code

As you might expect, there is no extra server-side setup to enable presence.  In the earlier user flow, we assigned users a token server-side. We used that token to initialize an Ably WebSocket from the frontend and join a channel.  Now, we need to set the user up for presence, once the channel is established.

```svelte
<script lang="ts">
	import app from '$lib/configuration';
	import type { Types } from 'ably';
	import { Realtime } from 'ably';
	import { onMount } from 'svelte';
	import type { PageData } from './$types';

	export let data: PageData;

	const { ablyChannelName } = app;

	let { myClientId, name, token } = data ?? {};

	let channel: Types.RealtimeChannelPromise | null = null;

	onMount(async () => {
		const ably = new Realtime.Promise({
			...token,
			authCallback: () => {	}
		});

		await ably.connection.once('connected');

		channel = ably.channels.get(ablyChannelName);

		await channel?.attach();

		await channel?.presence.enter({ name });

		await channel.presence.subscribe(async (presenceUpdate) => {
			const { action, data } = presenceUpdate;

			const updatedPresentMembers = (await channel?.presence.get()) ?? [];
			if (updatedPresentMembers) {
				/* logic to update UI with new presence data */
			}
		});
	});

</script>
```

Up to line `28` the code does not differ much from the earlier version.  We see presence for the first time in line `28`.  You access `presence` methods via the channel object, and users have to join the channel presence actively (joining is not automatic):

```typescript
await channel?.presence.enter(data);
```

`data` here can be a string or, like we have above, an object.  If opting for an object, make sure it is JSON serializable.  These data will be available (in client code) to all another users subscribed to the channel.  In fact, to receive presence data, we need to subscribe to the channel presence feed (as in line `30`).  The provided callback function is for the logic we want to run each time the client receives data on the presence channel.

For this game, we just need to update the list of available players in the user interface, when a new player enters.

Ably provides other `presence` methods; as well as `presence.enter`, there is a `presence.leave` method, again handy to update the interface, removing players who are no longer available, perhaps because they have started playing a game.  We can also use a `presence.update` method for custom updates.

### Example Presence Message

Beyond the data string or object, which we saw above, presence updates include an `action` and some other meta, such as a time stamp.  The `action` will be `enter`, `leave` or `update` and is helpful for filtering incoming presence data in the callback.

Here is an example update:

```javascript
{
  "id": "frkjZFEfH-:0:0",
  "clientId": "4a4f8b8a-0207-43d8-b027-ad9adf44dd82",
  "connectionId": "frkjZFEfH-",
  "timestamp": 1684862512507,
  "encoding": null,
  "data": {
    "name": "Micki"
  },
  "action": "enter"
}
```

Note, the `clientId` is assigned when we create the user token.  A client can potentially connect multiple times and each of these connections shares the same `clientId`, but has a unique `connectionId`.

## ⚡️ Presence Updates

Just like `presence.enter`, `presence.leave` and `presence.update` can include a data payload.  We can use that payload with `presence.update` to handle game invitation logistics.  As an example, when a user clicks the *Invite Micki* button, we can send a presence update:

```javascript
await channel?.presence.update({
	type: 'invite',
	sender: myClientId,
	target: player2,
	gameId,
	name
});
```

This is a custom data payload for the game.  All players on the channel will receive this, which is why we include the target player ID.  That can be used to filter presence updates in the `presence.subscribe` callback.  As well as letting someone know they have been invited to join a game, these updates could be used to update everyone&rsquo;s user interface; letting them know Micki has an open invitation.

The game includes similar channel updates for  accepting and rescinding an invitation.  Finally, when players agree to play, their clients will both send a `channel.leave` presence message.

As before, you can lift this code for use in a chat or other real-time app.  In a chat app, you could, for example, let users leave a custom presence message when they are stepping away from their computer for a few minutes.  See the <a href="https://ably.com/tutorials/presence">Ably presence tutorial</a> for more details on the API.

## 🤔 Svelte Real-time Multiplayer Game: What Next?

The game is by no means polished, and I am considering further features and services to improve it.  In terms of the real-time and WebSocket side of things, it probably just needs some minor tweaks.  The game is currently hosted by Netlify in a serverless environment.  It might be nice to use serverless Redis to keep track of top scores or even top players.  Let me know your ideas!

## 🙌🏽 Svelte Real-time Multiplayer Game: Wrapping Up

In this post, we had a look at presence and awareness for a Svelte real-time multiplayer game.  Although we focussed on a game, we saw, more generally:

- what **presence** and **awareness** are;
- how you might use **presence updates** to surface status changes; and
- how to use **Ably presence**.

Please <a aria-label="Open the Rodney Lab Git Hub repo" href="https://github.com/rodneylab/sveltekit-ably-realtime-game">see the full repo code on the Rodney Lab GitHub repo</a>. I do hope you have found this post useful and can use the code in your own Svelte real-time multiplayer game or app.  Let me know if you have any suggestions for improvements to the post.  Also reach out with ideas on new features to add to the game. Drop a comment below or <a href="https://rodneylab.com/contact/">reach out on other channels</a>.

## 🙏🏽 Svelte Real-time Multiplayer Game: Feedback

If you have found this post useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please <a aria-label="Support Rodney Lab via Buy me a Coffee" href="https://rodneylab.com/giving/">consider supporting me through Buy me a Coffee</a>.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via <a aria-label="@ask Rodney" href="https://twitter.com/messages/compose?recipient_id=1323579817258831875">@askRodney</a> on Twitter and also <a aria-label="Contact Rodney Lab via Telegram" href="https://t.me/askRodney">askRodney on Telegram</a>. Also, see <a aria-label="Get in touch with Rodney Lab" href="https://rodneylab.com/contact/">further ways to get in touch with Rodney Lab</a>. I post regularly on <a aria-label="See posts on svelte kit" href="https://rodneylab.com/tags/sveltekit/">SvelteKit</a> as well as <a href="https://rodneylab.com/tags/seo/" aria-label="See posts on search engine optimisation">Search Engine Optimization</a> among other topics. Also, <a href="https://newsletter.rodneylab.com/issue/latest-issue">subscribe to the newsletter to keep up-to-date</a> with our latest projects.