Fran Tufro

Decentraland Adventures: Part 2 - Catalyst

🗓 2022-08-057m.

I've been wanting to write this update for a while, but couldn't find the time to do so before. We've been busy working on the project and I'm currently taking some time off in NYC. But here I am, trying to get some words down before going to see mewithoutYou❤️ at Irving Plaza.

The first milestone in the Decentraland 2D Client proposal is to create a Rust client library for Catalyst servers. The library will, for now, only support the features that we need for the 2D client. I'm happy to say that we managed to get it done ahead of time, which gave us some time to experiment on different paths to take for the next milestones, but that's for another post.

What are Catalyst servers?

I'm not an expert on Decentraland architecture (not yet 😎) but I'll try to explain what I think I know, which might be wrong (and I hope you'll correct me if you know more than me).

In order to store assets (3D models, scene code, etc), Decentraland uses a distributed filesystem called IPFS. You can query IPFS directly to find all the assets required to render a scene, but I assume that performance is not great, especially when you have to download a lot of data. To simplify the consumption of content, the Decentraland Foundation developed a decentralized content network using what's called a Catalyst server.

Although the Foundation hosts or helps support most of the existing Catalyst servers, the vision is for them to be hosted by anyone in the community that has some hardware and spare bandwidth to help support the platform. You can setup a server yourself if you're up for it.

There are three main components to a Catalyst server: the Content API, that exposes all the API endpoints to work with Decentraland content. That's the main API we care about for this project. There is also the Comms API and the Lambda API, which, to be honest, I've not explored a lot so I don't feel I'm good at explaining what they're for. But you can always hop into the catalyst channel in discord to ask about them (I found everyone is super friendly there and always happy to help, which is awesome❤️).

Why are we using Catalyst

The prototype we're working on has two main requirements:

  1. Download 3D content scene to auto-generate 2D versions of buildings.
  2. Download 2D content scene to render inside the client.

We wanted a way to easily and cheaply host content for our 2D client, especially for this initial phase when we're developing it and things will change a lot. We decided to implement a library in Rust that connects to Catalyst servers to do so.

To be honest, the API docs were a great source of information. We got a script downloading scene content pretty fast, and then we just had to massage the code for the library to be nice to work with.

The Catalyst Quest

I started by reviewing the JavaScript catalyst client code, and noticed that I was not very in love with how things are done there, so I decided to approach the Rust library differently.

First of all, I made it really easy to use the servers provided by the foundation. There are three methods development, staging, production. Each of these methods return a client that can connect to those servers.

let server = Server::production();

This of course, is just a shortcut. Since the nature of catalyst is to be distributed and decentralized, you can create a client that connects to any arbitrary Catalyst node, even nodes that are not "official".

let server = Server::new("https://my-awesome-server.org");

Supporting this is crucial for us, since we want the ability to quickly iterate on content that is not deployed to official clients, we want to reduce the strain on the existing Catalyst network while we work on the 2D client. Once we have a clear idea on how things should be implemented, we can coordinate with the DAO servers to figure out the best way to deploy 2D content, but for now we'll iterate in a custom development server.

When you have a server defined you can pass it to a ContentClient to perform actions.

For example, if you want to get the Genesis Plaza scene file, here's how you'd do it:

let server = Server::production();
let parcel = Parcel(0, 0);
let scenes = ContentClient::scene_files_for_parcels(
               &server, 
               &vec![parcel]
             ).await?;

for scene in scenes {
    println!(" - {:?}", scene);
}

We're using a vector of one parcel (the "0,0" parcel belongs to the Genesis Plaza), you could add multiple parcels and it would return the scene files for all those parcels.

If you're curious you can always explore the examples. Feel free to open an issue / pull request if you find something odd. I'll be adding examples as we make more progress on the project, and fix those that are commented out for now.

I'm very committed to creating a library that is easy to use and very powerful. Because of that I created an interface (methods get and post and their raw versions for now) for users to be able to hit any endpoint of the Catalyst server, not just the ones that we need.

The interesting thing is that both get and post support returning any type that implements the Deserialize trait. So, as long as you implement the trait that transforms the result of the Catalyst server into your type, you can use it. And if for some reason you can't do that, you can always use the *_raw version of the methods and get the reqwest::Response to deal with it.

My hope is that this library will allow other developers to start creating tools that interact with catalyst using Rust. If you plan to do it don't hesitate getting in touch with me in the project's channel in the DAO server (or by email).

Project status update

Besides the update on catalyst, just wanted to do a quick review on where we're at, and what you can expect in the next post.

We've been working on multiple fronts: the runtime (to read existing scenes), the client (2d renering, animation, movement, etc) and art exploration.

The runtime is proving to be the first "hard" problem to solve, and much of my focus has gone into solving it. There are two main paths, and both have their pros and cons. I'll write an in-depth post next month when I'm back to explain the problem, both possible solutions and what I found exploring said solutions.

We've also done some progress on the client itself, we have been using Bevy engine to implement spritesheet-based animations and movement. I'll also create an in-depth post about my vision for this area of the project. We want to be able to support wearables and custom sprisheets, but that's a spoiler, so I'm shutting up for now.

pixelized genesis plaza core building

We've also been working on some concept art for the Genesis Plaza, click on the image for full resolution.

pixelized genesis plaza

That's it for now, let's keep moving!

character running