Online face code generator tool | Tweak facekeys and see how they work

Users who are viewing this thread

Swyter

Grandmaster Knight
Hey, guys. Guess what? Made a face code generator, like the one for terrain codes, ten years later:


Working with 64-bit numbers in JavaScript is terrible, but it works. I'll polish it a bit, maybe adding support for dropping custom skins.txt files and get the right tags/morph keys back for your race.
🐧


Another thing I have found out is that there's seemingly support for 43-ish face keys, each of them is a 3-bit number that goes from 0 to 7, but only 42 of them do something usable. The 43nd only has one bit and doesn't seem to do anything when you move the slider. You can still add more to the list, but the game won't use them.


It's interesting that, like for combobox overlays, the list elements appear reversed, so the first one (generally Chin Size) appears right at the bottom.

All in all, very cool to have the format documented now.


The funny thing is that I made this because I wanted to take advantage of the new face code operations in the module system to convert stringified numbers from a string register back into an actual number. Now that we know the bit layout; with the bit width and shift of each field, it can be done by exploiting the face code properties to retrieve the individual components, do some magic stuff to take into account the hexadecimal vs. decimal and bit position to reconstruct the number back.


Right now we can turn numbers into strings, but not the other way around. As far as I know.

Another interesting tidbit is that when you export/import a character the game only saves/loads face_key_1 and face_key_2, which is only the first half of the code you see when pressing Ctrl + E in the face editor. Ideally there should also be a face_key_3 and face_key_4, the former stores the face morphs 21 to 42, so that information gets lost. If you wonder about face_key_4, it is always wastefully empty. face_key_2 stores face morphs 0 to 20 (there's a wasted bit).

If they had spent their bit budget well there would be enough space for 64 morph keys in those last three blocks. ¯\_(ツ)_/¯



Face code internal format​

A face code is actually made out of four 64-bit (or 8 byte) numbers (or blocks) written in hexadecimal and concatenated together.

Here named from left to right (0), (1), (2) and (3).

When you export a character from the Character > Statistics page it will only save the left half of it, storing the (0) as face_key_1 and (1) as face_key_2. Meaning that anything after facekey20 (i.e. from facekey21 to facekey42) will be lost. This may or may not matter, depending on the mod.

Keep in mind that the game is very inconsistent in how it calls these codes; sometimes it refers to the whole face code as a «face key», sometimes a «face key» means each of the small face shape tweaks that you can control via in-game sliders, like in module_skins.py, here we use the second meaning. Take a look at the diagram below:

Code:
 face_key_1 = 180000041
 face_key_2 = 36db79b6db6db6fb

                                  <------- start-|
                  <------- start-|               |
  <------- start-|               |               |
0x000000018000004136db79b6db6db6fb7fffff6d77bf36db0000000000000000
  _______180000041
       (0)        36db79b6db6db6fb
                        (1)       7fffff6d77bf36db
                                        (2)       ----------------
                                                         (3)
                                                       (unused)

  Here is block (0) from the example above, we will use the bit shift and number of bits columns
  from the table below to build bitmasks and retrieve each field, using the Python 3 prompt:

  For example, age is in block (0), has 6 bits and a shift of 30 bits,
  using hex((pow(2, num_bits) - 1) << bit_shift) we get:

    >>> hex((pow(2,6)-1) << 30)
    '0xfc0000000'
    >>> hex((pow(2,6)-1))
    '0x3f'

    >>> bin((pow(2,6)-1) << 30) # swy: same thing, but in binary
    '0b111111000000000000000000000000000000'
    >>> bin((pow(2,6)-1)) # swy: what this does is just to generate six ones, six bits
    '0b111111'

  Now that we have the right bitmask we can use the logical AND operation to isolate only the bits
  we are interested in and shift them back to the right (we can also see it as removing the padding)
  to get the actual number with just a simple ((block & bitmask) >> bit_shift):

    >>> hex(0x180000041 & 0xfc0000000) # swy: only leave our six potential bits toggled
    '0x180000000'
    >>> bin(0x180000041 & 0xfc0000000) # swy: same thing, but in binary
    '0b110000000000000000000000000000000'
    >>> bin(0x180000041)               # swy: here's the original, compare against the one above
    '0b110000000000000000000000001000001'

    >>> hex((0x180000041 & 0xfc0000000) >> 30) # swy: we are interested in the left-most «110» bit part you see above
    '0x6'
    >>> bin((0x180000041 & 0xfc0000000) >> 30) # swy: so move the bits 30 positions to the right, same but shown in binary
    '0b110'

    >>> ((0x180000041 & 0xfc0000000) >> 30)
    6

||    Do:  0000000000000000000000000000000110000000000000000000000001000001
 |  Mask:  ----------------------------XXXXXX
 | Final:                              000110

  In our case the age field contains the number six. See more examples below.

  _______180000041
                3f # hair: to get the field ((0x180000041 & 0x3f) >> 0), which results in 1
               fc0 # beard
             3f000 # skin
          3f000000 # hair_color: to get the field ((0x180000041 & 0x3f000000) >> 24), which results in 0
         fc0000000 # age: python code to generate a bitmask: hex((pow(2,6)-1) << 30)

valueblock no.bit shift in keynum bitscomments
hair006Max bits known, adjacent to next left field (beard).
beard066Max bits known, adjacent to next left field (skin).
skin0126 (¿? unsure, maybe more)Check max bits for correctness.
hair_color0246Max bits known, adjacent to next left field (age).
age0306 (¿? unsure, maybe more)Check max bits for correctness.
facekey0013 * 0 (0)3
facekey0113 * 1 (3)3
facekey0213 * 2 (6)3
facekey0313 * 3 (9)3
facekey0413 * 4 (12)3
facekey0513 * 5 (15)3
facekey0613 * 6 (18)3
facekey0713 * 7 (21)3
facekey0813 * 8 (24)3
facekey0913 * 9 (27)3
facekey1013 * 10 (30)3
facekey1113 * 11 (33)3
facekey1213 * 12 (36)3
facekey1313 * 13 (39)3
facekey1413 * 14 (42)3
facekey1513 * 15 (45)3
facekey1613 * 16 (48)3
facekey1713 * 17 (51)3
facekey1813 * 18 (54)3
facekey1913 * 19 (57)3
facekey2013 * 20 (60)3
facekey2123 * 0 (0)3
facekey2223 * 1 (3)3
facekey2323 * 2 (6)3
facekey2423 * 3 (9)3
facekey2523 * 4 (12)3
facekey2623 * 5 (15)3
facekey2723 * 6 (18)3
facekey2823 * 7 (21)3
facekey2923 * 8 (24)3
facekey3023 * 9 (27)3
facekey3123 * 10 (30)3
facekey3223 * 11 (33)3
facekey3323 * 12 (36)3
facekey3423 * 13 (39)3
facekey3523 * 14 (42)3
facekey3623 * 15 (45)3
facekey3723 * 16 (48)3
facekey3823 * 17 (51)3
facekey3923 * 18 (54)3
facekey4023 * 19 (57)3
facekey4123 * 20 (60)3
facekey4223 * 21 (63)1Only one bit left, wonky slider in-game and face does not seem to change;
why not exploit the remaining bit range better? Don't ask me.
 
Last edited:
By the way, and a bit off-topic, but I can't be the only one hating the XenForo move and subsequent reorganization of the TW Forums. Previously you could see everything from the main page, The Forge was one click away, now it feels like there's categories upon categories of nested boards to the point one gets lost, and the fact that the modding section is segregated from the main one is also a bit backwards. Normal people won't look here, while previously you'd see a lot of cross-pollination of curious players and visitors.

I generally like what Janus does, and I also know SMF as a forum system was obsolete and hard to maintain. But this is absolutely atrocious, and a great way of killing your healthy community. I am sure that there are other factors at play here, like the recent Discord-for-everything fad, and that it's been a while since the games came out, but I'm pretty sure this one is at the top. It's not just blind nostalgia, it is legitimately worse conceived and implemented.

One example; I have been trying to format the table and every time I type 8) the forum silently turns it into an emoticon. Doesn't seem like there's anything like the [nobbc][/nobbc] tag from the old system, there was also a checkbox to toggle if you wanted automatic smiley conversion, now it does it every time.
 
Thanks very much for this tool. Having used your terrain code generator I noticed that it enabled users to create larger scenes than it was allowed by its Native counterpart (they all would be perfectly compatible with the game). I always wondered whether or not it was possible to do the same thing with HEX face codes as opposed to only HEX terrain codes. Is it though? Having the opportunity to make very deformed faces would be very appreciated!
By the way, and a bit off-topic, but I can't be the only one hating the XenForo move and subsequent reorganization of the TW Forums. Previously you could see everything from the main page, The Forge was one click away, now it feels like there's categories upon categories of nested boards to the point one gets lost, and the fact that the modding section is segregated from the main one is also a bit backwards. Normal people won't look here, while previously you'd see a lot of cross-pollination of curious players and visitors.
After the XenForo transition in 2020 things have not been the same... Now this place is obscured and does not enjoy that much popularity as it used to in the past.
 
Improved the thingie a bit, now the buttons behave like the ones in the game.

unknown.png

It also supports dropping a custom skins.txt and choosing a race from the list to get the right mesh names. It's ugly, but everything is more or less in place.
 
Just for completeness, Earendil told us on Discord of a handy tool from 2019 by Marnid called MB Studio that seems so support previewing troops using the OpenBRF library to load assets, it can probably work in tandem with mine: https://github.com/djaessel/MB-Studio

The ModDB pages were seemingly deleted, but maybe there's a way to reupload the precompiled version somewhere. If not, the source code is still up.

I haven't really been up to date with what has been going on here, but I'm slowly catching up. A lot of great utilities and fun advancements since 2017. Props to you, guys. ¯\_(ツ)_/¯
 
Last edited:
Thanks very much for this tool. Having used your terrain code generator I noticed that it enabled users to create larger scenes than it was allowed by its Native counterpart (they all would be perfectly compatible with the game). I always wondered whether or not it was possible to do the same thing with HEX face codes as opposed to only HEX terrain codes. Is it though? Having the opportunity to make very deformed faces would be very appreciated!
Any information if it is possible to do the above?
 
Any information if it is possible to do the above?
The deformer sliders end up being normalized values in the -1.0 to +1.0 range, I think. So it depends on the actual values one puts in the skins.txt file as a mod developer.

Because my tool lets you set any field to any possible value within the available range you can probably contort faces more than usual, mainly because the in-game sliders have a set of restrictions where if slider X is bigger than A slider Y must be limited to B. You don't have these constraints here.

We have all seen the pygmy heads when the face codes are zeroed out or used in special code troops. Now you have full control about that, careful about choosing skin texture indices outside the normal range. It probably won't crash if the game is clamping the values correctly, but you never know.

Give it a whirl and let me know what you guys think. :party:
 
Last edited:
By the way, you may have noticed that the in-game deformation sliders seem to have a more nuanced and precise range than mine.

Well, that turns out to be a temporary illusion; if you click on Done and go back to the face editor you will see how they stick to one of the eight available positions, even if they weren't lining up before. Smoke and mirrors.

Three bits, available range from zero to seven. Middle point being three, later remapped (or well, normalized) to negative to positive one.

So 0 is -1.0, 3 is 0.0 and 7 is +1.0, I believe. Not a lot to work with, but I guess nobody has noticed until now. :)
 
Turns out the hair and beard mesh indices were off by one because I was missing adding an entry for no hair at all. Also fixed some small parser mistakes and improved the styling and layout. Now every time you change the code, the URL will also change, so that you can go back and forth using your browser's history function and it works a bit like a handy undo/redo. You can easily share and save links with specific codes.

If you dropped a custom skins.txt and it is no longer saved in your browser's local storage, falling back to Native again, it's because the face code page flushes older, known-bad parsed versions on purpose and resets the state. Drag and drop the file again and, boom, done.

PS: I was searching previous discussions about this (you know, prior art) and I found these from 2006 and 2015.
 
Turns out the hair and beard mesh indices were off by one because I was missing adding an entry for no hair at all. Also fixed some small parser mistakes and improved the styling and layout. Now every time you change the code, the URL will also change, so that you can go back and forth using your browser's history function and it works a bit like a handy undo/redo. You can easily share and save links with specific codes.
Fascinating what all is possible, thanks for the work here!
I am sure that I have looked up every tool but forgot again about the second link of yours. It might also be that I just did not want to install another little tool, your html work is more handy at this. I missed the post of the first linked but I find it also difficult to understand and that it is something with Pearl might have deterred others :lol:
 
Hey, sorry for the disappearing and all that crap in case you noticed.
Thank you for mentioning my tool although you thought it was made by Marnid.

Actually the Version name of the tool was meant to be Marnid since I planned to give each major version a name.
Like a name from all the native original npc characters.

I think the first was Klethi or something I used.

Sorry for deleting it all.
I actually reuploaded the source code under a different name (djaessel), since that was gone as well.

The version that was on ModDB is gone forever in case noone got a backup or has that thing downloaded somewhere.

Because I also deleted the sourcecode and all of that and many more things... yeah... a lot of **** happened.

Luckily I found an older version that was from one year prior or something. Not much might be different but I know that I had fixed some bugs in the final version that was on ModDB, just cant remember what it was.

If someone would still have that installer/release exe somewhere I might be able to decompile/analyze it and find what I changed in case anyone would be interested. But could take some time maybe, depending on whether I just have to use one tool for it and all is clear or not. Because I might added some decompile protection, just not sure.
Otherwise you could just use ILSpy or something and get the source from that one yourself.

Yeah all about decompiling xD

Maybe my tool could be use for some of you to maybe develop something on top of it or something else.

Thank you Swyter for giving it a star and maybe investigating it, in case you got some ideas from it for your own projects.
Back when I started I liked your work and got inspired by it.

And Eärendil, sorry that I left without a word I think. I was in a real bad place to say the least.
Hope you keep doing your thing and thanks for supporting me back then while no one else really seemed to do.

How did the new Modding tool work out or did you stop on it?
I know we wanted to kind of reprogram parts of mine "MB Studio" and create something new and better.
Cross platform and all.

But it seemed only you were real pumped about it and me at times.
Hope you two guys are doing well out there.

Thanks for what you did and may my work aid you in some way.
 
Nice to read again something back of you, @Johandros , I hope you are doing well!
The version that was on ModDB is gone forever in case noone got a backup or has that thing downloaded somewhere.
I might still have the latest update of moddb at my old laptop, will take a look and give you an info.
How did the new Modding tool work out or did you stop on it?
At the moment work is focused on the modding guide which got a html-update (and thanks to Swyter an online version):
https://earendil_ardamire.gitlab.io/modding-guide/
It is planned, beside completing the informations at all the sections, to integrate little tools into it, to make parts of it easier for newcomers, the face code generator here is also still on my to-do-list for integration, a terrain code editor is already inside. Doing it all at html seemed to be a more reasonable approach which was also easier to achieve.
 
Great to hear all that! :smile:

Hope you are well as well and I am alright for now.

The webpage looks pretty great from the first look! Nice work!
Maybe at some point I could also add some tool or something to it, in case you might need help with it.
But I cant promise.
 
The official thread and GitLab for it is here:

Feel free to work at something if something comes up your mind but don't feel obligated to. We are happy about every contribution :grin:
 
Back
Top Bottom