My first memories of working at Bhoos are of the games we played after lunch. Back then, we'd gather to enjoy a few games of CallBreak with a deck of cards. One of us played the role of the dealer, handling the shuffling, dealing, and keeping score. Little did anyone know, behind the scenes (right after lunch), that we were secretly cooking up a mobile version of call break. In no time, we had a working prototype, and our lunch breaks turned into play-testing sessions. Sure, some early hiccups made our game crash, but we ironed out the wrinkles, and after that, there was no looking back. No more dealing with old, wrinkly cards (they wore out fast because of our intense use!). Everything flows effortlessly on our phones now, and while a hint of nostalgia lingers, we don't miss the old ways nearly as much.
The tradition of playing Call Break after lunch continues to thrive here at Bhoos. I'm truly grateful to be part of such a dedicated team that shares the same passion for our product as our biggest fans. Beyond Call Break, we're actively developing various other games, including Marriage, Ludo, and an exciting SUPER surprise game that we'll announce soon!
Regardless of how many new games we introduce, they all rely on the same foundational technology and development ethos. In this blog, I aim to examine the code that makes gaming over a hotspot possible. I want to provide insights and understanding to anyone interested in building similar games or services so you can grasp the essential components that make these experiences come to life.
Let's jump right in, beginning with how games communicate over a shared network. While game rules and animations define the heart of a game, have you ever wondered how players connect and assemble around a virtual table to start playing? What happens when you press that inviting "Host" button? Conversely, how do other players seamlessly join the game you're hosting?
Enter UDP sockets
Our game uses UDP (User Datagram Protocol) sockets to establish connections between players and facilitate gameplay. UDP is a lightweight, connectionless protocol that doesn't guarantee the delivery of data or maintain a connection state. While this sounds like a limitation, it's precisely what makes UDP perfect for playing games over hotspots or in the same local network where players are often in close proximity to each other, which reduces the likelihood of data loss or interference. The minimized overhead associated with not needing to establish and maintain connections translates to lower latency, which is crucial for delivering a smooth and responsive gaming experience.
The code below illustrates how a client can send data to a server using UDP. It's that straightforward; with UDP, there's no need to establish a connection—simply send your message to a known IP(localhost in this case) and port(which is predetermined), and it's on its way, no recipient action required.
server.js
import * as dgram from 'dgram';
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`Received message from ${rinfo.address}:${rinfo.port}: ${msg}`);
});
server.bind(3000);
client.js
import * as dgram from 'dgram';
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello, server!');
const sendMessage = () => {
client.send(message, 3000, 'localhost', (err) => {
if (err) {
console.error(`Error sending message: ${err}`);
} else {
console.log(`Message sent to server`);
}
});
};
setInterval(sendMessage, 3000);
You can use ts-node to run both of the code above (one after the other in the same computer) and see that it works! While this doesn’t do much, it shows how easy it is to start using UDP sockets. However, in the real world, i.e., when mobile phones are connected to the same network, we can't simply use "localhost" as the address; we'll need the local IP addresses of the other players' mobile phones. In UDP, this is typically achieved through UDP broadcast, which allows a single message to be sent to all devices on a local network. Clients wishing to connect to a host initiate this process by broadcasting a message known as a "discovery packet" to all devices on the network. When a host receives this packet, it also acquires the IP address and port of the sender (i.e., the client). With this information, the host can then send "room info" directly to the clients. At this point, a room appears on the phones of other players, allowing them to click on it and select "Join.”
The "discovery packet" can be as simple as an empty message, whereas the "host info" packet contains all the essential information for a player to join a game. This includes details such as the room name, the list of clients already in the room, the game name, and the game configuration. The game configuration is game-specific and holds information like game rules or modes.
In the example above, we transmitted a straightforward string, "'Hello, server!," over UDP by simply writing it to a buffer and sending it. However, when dealing with larger objects, such as the "host info," it becomes necessary to serialize the data before sending it and deserialize it upon reception. Serializing data means converting it into a format that can be easily transmitted as a stream of bytes and later deserialized back into its original form on the receiving end. At Bhoos, we use an in-house library dedicated to handling serialization. This library guarantees the efficient transmission and reconstruction of complex data in our games and is a potential topic for a future blog post all on its own.
Let's walk through the entire process step by step
- A player initiates a hotspot on their device, inviting others to connect.
- Each player launches the game and enters the "Hotspot screen," which sets up a UDP socket.
- One player configures the game settings and starts to host a game which makes them the host.
- The clients or rest of the players send out a 'discovery packet' to all devices on the local network.
- The host receives these discovery packets and promptly responds by sharing game configuration with all clients.
- Players can now spot the available room and decide to "Join" it.
- The host maintains an updated list of clients, including the newcomers, and forwards the revised room info to all players.
- With the game officially underway once the host presses “Start”, each client communicates by sending and receiving game data over UDP, much like they would if playing online.
I hope that the next time you gather with friends or family to enjoy our games(CallBreak, Marriage, Ludo). Now, you have an understanding of how they're all connected, but, there is so much more to uncover!
Ever wondered how game rules are implemented or the inner workings of animations? These are just a few of the questions we'll be tackling in our upcoming blog posts. Stay tuned, as we're eager to uncover these mysteries alongside you!