Hey there!
In this article, I'm going to explain how you can render a pretty figure like this one:
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.
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.
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,
}
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
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:
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
hr-679-61
: Hair with key 1012
and color 61
ha-1012-110
: Hat with key 1012
and color 110
ch-804-1341
: Shirt with key 804
and color 1341
lg-275-110
: Trousers with key 275
and color 110
sh-3089-110
: Shoes with key 3089
and color 110
Notice: the figure part
key
is different from the figure partid
, as you can see in theFigure 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
:
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 apalleteid
to a dictionary of colors.settype
keeps track of thepalette
, 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
}
]
},
}
}
}
}
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 thelibs
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,
}
}
}
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 hairlib
h
: the image size (it could besh
if it were zoomed out). At Open Hotel we're not usingsh
images, since zoom is handled by pixi-viewport-
std
: the image's action.std
is the standard, but it could bewlk
for walking, orsml
for smile.For some reason, the action
mv
matches the files with thewlk
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 ishair
.4
: the figure part id for this specific hair.2
: the position, which can vary from 0 to 7 rotation clock-wise
-
0
: the animation frame. Actions likestd
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)