Argus, a onchain game developer and publishing company, has created the World Engine, an in-house engine designed to overcome technical limitations of onchain gaming. The World Engine is a sharding layer 2 SDK, featuring a loop-driven runtime and sharding for improved scalability, both of which are more suited for gaming applications.
The World Engine separates the smart contract related logic and the game execution logic into the EVM base shard and game shard respectively. The EVM base shard uses a framework called Polaris to leverage existing Ethereum developer tools and infrastructure, while interacting with the game shard through a router.
Argus's World Engine's potential application is illustrated by a case study of an onchain visual novel game. The game, created during the Interchain Hackathon, connects Cardinal, Nakama (an open-source game server), and a user Client to deliver a multiplayer online visual novel experience.
Games are hard to make, but Fully Onchain Games (FOCGs) are even harder. Among the notable attempts to bridge this gap, today we're taking a look at Argus and World Engine.
Argus traces its roots back to the first generation FOCG, Dark Forest. With over 10K+ players in less than a week and filling up most of Gnosis Chain's blockspace at the time, Dark Forest is a game that is historic for demonstrating the potential of FOCGs. Scott co-created Dark Forest and I wonder if his experiences during this time may have led to founding Argus.
Source : designboom
World Engine is the first thing that comes to mind when you think of Argus, but Argus is wary of being seen as an infrastructure company and describes itself as a game development and publishing company. Why? I found the answer in this podcast. The World Engine was created by Argus as a in-house engine so that they could create on-chain games and not be limited to the technical options that exist today. This infrastructure was only made public so that other game studios could use it. In other words, the emphasis is on "making fun games." In fact, just looking at their website, it appears that they currently have about three games in development using the World Engine.
If we look at the early days of the traditional gaming industry, the most popular game engines were not created intentionally, but rather were created and shared by game studios to make their own games, and we can assume that in the on-chain gaming industry, the most useful game engines will come from game studios making a variety of games, not from companies specializing in on-chain gaming infrastructure.
Source: Argus
Many of the technical limitations and constraints associated with on-chain gaming are fundamentally due to the fact that we're trying to build games on a blockchain that wasn't designed for games in the first place, and many projects that claim to be chains for games are actually chains for NFTs. With this background, World Engine is a sharding layer 2 SDK built from the ground up with game developers and players in mind.
The main features of World Engine are as follows:
First, it's a Loop-driven runtime. Most existing dApps, such as Uniswap, use an event-driven runtime that responds to user input. However, this is not ideal for games, for example, in games like Minecraft, elements like weather and gravity need to be constantly updated regardless of user input. Games prefer a loop-driven runtime, where the state is updated in a defined loop within a single tick. Also, its more common for games to have a more or less fixed order of state changes within a single tick. However, event-driven runtimes are not suitable for games because the order in which transactions are executed can always change due to many factors, so Loop-driven runtimes are better suited for games.
Next up is sharding. Since Layer 2 is also a computation platform, when it reaches a certain level of players, certain measures must be taken for scalability. The usual way is to spin up another rollup, but then you run into the problem of interoperability and fragmentation between rollups. Using a shared sequencing layer, which is a trend nowadays, can avoid this problem to some extent, but it also introduces new problems, such as having to rely on slashing and being vulnerable to DOS attacks. For this reason, World Engine uses a sharding approach that is inspired by the server structure of traditional MMO games. The actual sharding can vary depending on the game company: each region can be segmented and assigned to a different shard, or each server instance can be assigned to a shard like a channel in MapleStory. Each shard is asynchronous with each other by default, so things like atomic bundles between shards are not possible, although there is little need for two chains to be synchronously compatible unless its DeFi.
Finally, there's composability. Argus envisions the Intergame Thesis, which is not just compatibility between games, but compatibility between stakeholders in the on-chain game industry, such as game publishers, marketplaces, modders, etc. In order to fulfill this Intergame Thesis, a common standard or system is needed, and the World Engine is currently trying to fulfill that role.
By separating the logic related to smart contracts from the EVM base shard and the logic related to game execution from the game shard, World Engine can combine the compatibility of blockchains with high-throughput game servers.
Source: Argus
Earlier, we mentioned that World Engine uses sharding, and all the logic related to smart contracts is handled on this base shard. The EVM base shard is a generic EVM rollup that still leverages developer tools and infrastructure from the Ethereum ecosystem, and interacts with the game shard later on via a router. The EVM base shard is where developers, modders, and players can deploy various game-related services such as marketplaces and DEXs. Argus implements the EVM base shard through something called Polaris.
3.1.1 Polaris
Polaris is a framework, or plugin, created by Berachain, whose main purpose is to allow any chain to use the Ethereum equivalence level EVM. For example, you can use Comet as a consensus layer, the Cosmos SDK as an execution layer, and then Polaris as a runtime layer on top of that to get the same level of EVM as Ethereum.
By separating the base layer from the EVM runtime layer, Polaris allows developers to try different things on the base layer without breaking the EVM. Adding custom precompiles is expected to become even easier with the Precompile Development Kit, which is currently in the works. Polaris' Stateful Precompile also has access to Cosmos' application and consensus layers, allowing you to use Cosmos modules like Staking and Authz through the EVM.
3.1.2 Back to World Engine
Using Polaris' customizability, World Engine's EVM base shard has the following features:
It has a specialized gRPC server, so that later game shards can connect to the EVM base shard to submit and store transactions. Note that gRPC has many advantages over JSON-RPC, such as being more efficient and supporting different programming languages and streaming types.
A special precompiles of EVM base shard allows messages to be passed from the smart contract to the game shard that implements this gRPC server.
The EVM base shard is connected to Celestia, the Data Availability layer, via Rollkit, which you can read more about in this article and watch this video to learn more about using Rollkit with Polaris.
All the logic involved in running a game is handled by a game shard, and game developers can use an existing game shard or create a new one for their game. Cardinal is the first game shard implementation created by Argus.
As the first game shard, Cardinal has the following features:
Native support for ECS frameworks commonly used in game development, making it easier for game developers to adapt.
Supports a tick-based, loop-driven runtime, supporting up to 20 ticks per second.
Game logic can be written in Golang.
Compatible with game engines like Unity, Unreal Engine, etc.
No need for a indexer.
You can see an example game using CardInal on Argus's GitHub.
This is an independent, arbitrary understanding and use of the World Engine while participating in the Interchain Hackathon, so it may be incorrect and likely not the optimal way to use the World Engine. It's recommended that you view it only as a "this is how you can use World Engine" kind of thing. The full code can be found on the following GitHub:
The game we wanted to create is a multiplayer onchain visual novel game that uses the GPT-4 API to make users feel like they're actually talking to an in-game NPC, and the first player to reach a 100 Likability rating with the NPC wins the match.
Our game didn't require any modifications to the EVM base shard as we didn't need to add smart contract logic to the existing EVM base shard, but there were three main components that we needed to focus on:
Cardinal: We forked the 'stater-game-template' from the Argus GitHub to use the existing Cardinal, and only modified the game logic to fit our game.
Nakama: Nakama is an open source game server created by Heroic Labs that provides many of the elements needed for multiplayer games. In this example, Nakama is used to connect Cardinal and Client.
Client: We used Next.js as the interface for users to view and play the game directly.
The relationship between Cardinal, Nakama, and Client as we understand it is as follows:
Input from the user occurs.
Client passes that input to Nakama via an RPC call.
Nakama passes the transaction corresponding to the RPC call to Cardinal.
Cardinal receives the transaction, executes it on the next game tick, updates the game state, and generates a transaction receipt (tx receipt).
The transaction receipt is passed from Cardinal to Nakama.
The client subscribes to dispathcer and receives the transaction receipt from Cardinal periodically and updates the client state.
4.3.1 ECS Model
Before we look at Cardinal, let's talk about the ECS structure first. The inheritance-based structure that we typically use when programming may not be efficient for large-scale multiplayer games. In the example below, we currently have a class called 'Mammal' and a class called 'Bird' that inherit from a class called 'Thing'. If we wanted to add a platypus, we could not inherit from either of these classes and would have to create a new class. In a real game, there are many times when you need to add new game objects like this, and an inheritance-based structure may not be appropriate.
Unlike inheritance-based structures, ECS emphasizes modularity by separating each part into the following parts:
Components: Components are the core of the ECS model and hold only data. For example, a "Health" Component contains only health metrics, and a "Location" Component contains only coordinate values for the current location.
Entity: An Entity acts as a container that includes multiple Components that are identifed with a unique identifier. For example, a particular Entity may contain Components such as 'Health', 'Location', 'Player', etc. that will be used to represent a user.
System: The logic that accesses or modifies a particular Component. For example, 'attack_player' affecting the 'Health' component, 'move_player' affecting the 'Location' component, etc. would all be System.
4.3.2 Transaction Receipt
Since Cardinal does not process transactions as soon as they are received, it first passes the transaction hash value to Nakama, and then generates and delivers a receipt with the hash, result, and any errors after the transaction is actually processed.
4.3.3 Code Example
In our game, we defined new player and likeness components and implemented the logic for them in the ECS model, but let's see how we added the player as an example.
First, we define a 'Player' Component, which only holds data about the player's name.
Next, we first define a 'CreatePlayer' transaction that triggers the creation of a new Player when a user joins the game.
Upon receiving the above transaction, Cardinal will run a 'PlayerSpawnerSystem' that will actually create the player. As you can see in the code below, when the PlayerSpawnerSystem receives the 'CreatePlayer' transaction, it creates a new Entity with a player and a likeness Component.
Finally, in the 'main.go' file, we need to register the newly created Components, Transactions, and Systems with the 'world' object.
Nakama 1) provides a connection between Cardinal and the client, and 2) provides many of the functions of a multiplayer game server. For example, user authentication, session management, match setup, etc. can be easily implemented through Nakama. There are SDKs and guided examples for virtually every game-related language, including Javascript, Unity, and Godot, so even those of us new to Nakama could get started. For our team, we implemented our client in Next.js, so we relied heavily on a Nakama + Javascript example called ‘xoxo-phaserjs’.
4.4.1 Nakama w/ Cardinal
The 'starter-game-template' provided by Argus is a slight modification of Nakama to make it work better with Cardinal, so if you want to create a game using Cardinal, you can use this template. When you use the Starter-game-template, Nakama RPC endpoints are automatically created for the transactions you previously registered with the 'world' object.
When a new player starts a Cardinal-based game, the first thing they need to do is set up a Persona Tag. This Persona Tag is stored in Nakama to generate a signing key for that user, which will automatically sign and send future transactions submitted by that user to Cardinal. This is why the 'claim-persona' and 'show-persona' RPC endpoints already exist by default.
4.4.2 Example code
We implemented the Nakama part by using a combination of 'starter-game-template' and the aforementioned 'xoxo-phaserjs', the part that connects Nakama to Cardinal uses the existing implementation of 'starter-game-template', and the part that connects Nakama to Client uses the aforementioned 'xoxo-phaserjs' project by default with some modifications.
To connect Nakama and Cardinal, the first thing we need to do is allow new users to set their Persona Tag, so we imported the 'claimPersonaTag' function from the 'starter-game-template'.
We also added logic to create a new match if no players are currently looking for a match, and to start the match if there is already a player looking for a match. You can also set a minimum or maximum number of players for this part, depending on the needs of your game.
Finally, we added a 'createPlayer' function so that the client can make an RPC call to the 'CreatePlayer' transaction that triggers the creation of the new player we created earlier.
4.5.1 Code Example
Our goal is to have the following happen when the user presses enter with their name on the page.
Authenticate the user
Set the name entered by the user as the Persona Tag.
Create a new entity with 'createPlayer'.
Find a match.
Here's how we implemented it in the code:
The core idea behind World Engine is to have an experience and throughput that is as close to traditional game servers as possible, without sacrificing the composability that is the biggest advantage of blockchain. We can't wait to see what games Argus has coming down the pipeline, and hopefully the "Why not build Onchain?" question that Scott was talking about will be asked by game developers in the near future.
Building Complex Real-time Onchain Game With World Engine - Scott Sunarto (Argus)
Scott Sunarto - Crypto Gaming, Argus Labs, and the Infrastructure vs. Application Debate
The Intergame Thesis: Endgame for Onchain Games - Scott Sunarto
Thanks to Kate for designing the graphics for this article.
We produce in-depth blockchain research articles
We explore the history of various gaming platform categories that have driven the success of the gaming industry, and Iskra's new vision and initiatives for Web3 gaming adoption.
A look back at 2023 in the on-chain gaming industry, and a look ahead to 2024.
Onchain Games I Played This Month: November
This report covers the gaming sector in November 2023.