DEV Community

Patrick Stival
Patrick Stival

Posted on

Habbo: Avatar Rendering Basics

Hey there!
In this article, I'm going to explain how you can render a pretty figure like this one:
angry

The avatar images in this article were rendered using Open Hotel Client. If you like habbo or games development in general, please consider contributing to the project or joining the team. My e-mail is at the bottom of this article.

Oh right, and it can also walk, swim, lay and face 8 different positions! Sounds like a lot of work, and it's indeed something susceptible to a bunch of edge cases.

The goal here is to learn how Habbo handles their assets to build an avatar.
std

Naming convention

An avatar figure is built using a combination of multiple body and clothing parts. You can use the habbox standalone avatar imager to try some combinations and get a string that describes your character.
habbox

At Open Hotel, we provide the same options as the habbox standalone imager for the avatar rendering (which is also the default habbo api pattern). Those are:



{
  look: 'hd-180-1.hr-110-61.ch-210-66.lg-280-110.sh-305-62',
  action: 'mv,respect',
  direction: 2,
  head_direction: 2,
}


Enter fullscreen mode Exit fullscreen mode

Figure parts

In this example, our encoded avatar figure is:



hd-195-1.hr-679-61.ha-1012-110.ch-804-1341.lg-275-110.sh-3089-110


Enter fullscreen mode Exit fullscreen mode

Each figure part is separated by a ., and each one of these parts can be described as:
figureType-imageID-colorID1-colorID2...-colorIDn

Actions

Actions change the way we build the avatar figure. Take by example the std, laugh and mv actions:
actions

Notice that multiple actions can occur at the same time, like sitting and waving. According to the action applied, some body parts might stay the same, while others are changed.

Figure Parts Example

Combining parts

Let's try to render them separately at Open Hotel and see what we get:

hd-195-1: Body + face with key 195 and color 1
hd

hr-679-61: Hair with key 1012 and color 61
hr

ha-1012-110: Hat with key 1012 and color 110
ha

ch-804-1341: Shirt with key 804 and color 1341
ch

lg-275-110: Trousers with key 275 and color 110
lg

sh-3089-110: Shoes with key 3089 and color 110
sh

All figures combined:
all

Notice: the figure part key is different from the figure part id, as you can see in the Figure Data section of this article.

Take a look below at the hairs hr-110-61, hr-677-61, hr-3048-61, hr-165-61. All of them with color 61:
hairs

Figure Data

Open Hotel provides a file called figuredata.json. This file holds information we need to get the right image for each one of our figure parts.
It is based on habbo's figuredata.xml, but we converted it to json to make it easier to use.

By using it, we can selectively lazy-load the image files as we need, since it wouldn't be practical to load everything in memory at once.

It basically holds two first-level keys:

  • pallete is a dictionary that maps a palleteid to a dictionary of colors.

  • settype keeps track of the palette, the metadata (like gender) and the images we need to use for each figure part.

Let's try a step-by-step render for the hr-679-61 figure (hair 679 with color 61). Since it's a hair, it's held under the hh_human_hair lib.



// figuredata.json
{
  "palette": {
    // 3. get color "61" hex from palette "2"
    "2": {
      "32": { "color": "DFA66F" },
      "61": { "color": "2D2D2D" }
    },
  },
  "settype": {
    // 1. Access the figure type, which is "hr"
    "hr": {
      // 2. Access the palette with id 2
      "paletteid": "2",
      "set": {
        // 4. Get hair with key 679
        "679": {
          // Both genders accept this hair
          "gender": "U",
          "parts": [
            {
              // 5. Since type is hr, get this part 
              // id and move to figureMap.json
              "type": "hr",
              "id": 27,
              "colorable": 1,
              // for part sets with more than one
              // color, multiple color indexes can be used
              "colorindex": 1
            },
            {
              // hrb is used when the avatar is using a hat
              "type": "hrb",
              "id": 27,
              "colorable": 1,
              "colorindex": 1
            }
          ]
        },
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Figure Map

The figuremap.json holds the libraries names mentioned at the Naming Convention section.

At figuremap.json, the first-level keys are:

  • libs
    An array with all the libraries names.

  • parts
    A dictionary that maps a partset name and a part id to an index of the libs array.

To get the lib we need, let's follow the steps:



// figuremap.json
{
  "libs": [
    // ...
    // 3. Get the lib id from the 1004th position of the array
    { "id": "hh_human_hair" },
  ],
  "parts": {
    "ha": {
      // ...
    },
    // 1. Access the "hr" partset
    "hr": {
      // 2. Access the part with id 27 and get its lib index
      "27": 1004,
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Now we have all the information we need to get our hair image, we just need to build the image file name.

Image files naming

The resultant file name should be:
hh_human_hair_h_std_hr_4_2_0, where each part of the file indicates:

  • hh_human_hair: this file is a part of the human hair lib
  • h: the image size (it could be sh if it were zoomed out). At Open Hotel we're not using sh images, since zoom is handled by pixi-viewport

  • std: the image's action. std is the standard, but it could be wlk for walking, or sml for smile.

    For some reason, the action mv matches the files with the wlk action name. This mapping happens at animations.json. I might cover animations in detail in a future article.

  • hr: the figure part, which in the case is hair.

  • 4: the figure part id for this specific hair.

  • 2: the position, which can vary from 0 to 7 rotation clock-wise

positionsN

  • 0: the animation frame. Actions like std only have one frame (frame 0), but for animations like walking (mv) and waving(wave), more frames are required.

Conclusion

This tutorial might be confusing, but that's because a lot of mappings are required, and animating can get even more complicated.

The goal here is to provide a general idea of how the rendering process works at Habbo and also encourage people to contribute to Open Hotel.

The current client active branch is structure-migration. If you run this branch, you should be able to look at the code that actually rendered the images present in this article.

If you're interested in contributing or have any questions, you can contact me at trickstival@gmail.com.

Thanks!!

Top comments (0)