Nodes revisited

When I was saying node overrides are the same as Photoshop layers I didn't tell the whole truth. Not out from malice or setting one of those traps I like to set you up to, but because I simply forgot about them because of lack of use.

And I didn't use those because I didn't know what the hell to put in there, but oooh I do know now.

As I say in this page, you won't find ANYWHERE else whatever I write in here (otherwise, I wouldn't be writing it), but this is even more true for this topic.

Argh! Not the nodes! My eyes, my eyes!

This movie is one of humanity's greatest achievements ever.

This was another of those arcane parameters no one tells you how to use.
I was so desperate for answers that, despite my well known misanthropy, I crept out of my cave and actually tried to get help.

... just to be promptly ignored.
And that's why I don't even bother to ever ask about anything, I swear.

Turns out that Minion in that topic was actually telling the truth, but only the part of the truth that worked for him.

But thanks to these articles I've been writing I got a clearer idea on this topic, got out to do some experiments myself and I finally managed to make this fucking "what the fucking fuck should I fucking put on this fucking function that fucking asks me for a fucking node name???" beast to bite the dust.

I was usually the other way around.

Let's talk again about my favorite topic: naked bodies ( ͡° ͜ʖ ͡°).

Nodes and bodies

Not only NiOverride.psc has functions that deal with nodes, but NetImmerse.psc too.
All those functions sound kind of useful.

... if I only had one node!!!

It pays to remember that I told you naked bodies are armors.

That applies not only to antropomorphic Actors, but to creatures as well.

When the minion said you should open the nif model in Nifskope to see the nodes, he was talking about creatures and he was right.

So, if wanted to change that creature's torso diffuse texture with a node override, I would do[1]:

AddNodeOverrideString(spider, true, "HumBody", 9, 0, pathToSomeTexture, true)

But if I tried that with an antropomorphic Actor, results aren't guaranteed.

Armors once again

You see, with creatures you have a great certainty you will find a node you've taken out from the *.nif file because CREATURES BARELY CHANGE ARMORS AT ALL[2].

That doesn't happen to humanoids. They change armors all the time, and if you are anywhere near as a pervert as me (who am I kidding "if"?), they get naked all the time.

The problem is this: not all armors have the same nodes.

Logical pitfall

You would wrongly expect (just as me) that the nodes you need are on the naked body and you only need to use those, but you may be wrong.

The Skyrim engine takes the nodes not from the naked body, but from the currently equipped armor.

The only time you are getting the naked nodes is when the Actor is... duh... naked.

Say, if you are naked and using CBBE 3BA, you would get your node name by left clicking on the skin and looking at the panel to your left when looking at the nif file in Nifskope:

"3BA" is the node.

But that "3BA" node won't work on an armor like this:

Has no "3BA" node, but "3BBB".

Now you see why node overriding for bodies is a problem?

Solutions

You need to create a function that checks for every single possibility and returns the one it finds (an invalid node name if it didn't).

Here are some dirty SAMPLE FUNCTIONS that get node names for some body parts.
Hopefully now you have an accurate idea of where you should look for node names and why.

Body

This sample is for women and CBBE bodies only.

Feel free to investigate the node names for UNP, BHUNP, UUNP, BHUUNP, UNP_OMFGWTFLOLBBQ, 7B, SAM, HIMBO... and put them in this function:

string Function GetBodyNode(Actor npc)
  If NetImmerse.HasNode(npc, "3BA", false)
    return "3BA"
  ElseIf NetImmerse.HasNode(npc, "3BBB", false)
    return "3BA"
  ElseIf NetImmerse.HasNode(npc, "CBBE", false)
    return "CBBE"
  EndIf

  return ""
EndFunction

It's a really dirty sample that needs work, but gets the job done.

If you are curious about how I would do it, this is an easily extendable function using JContainers[3].

string Function GetBodyNode(Actor npc)
  int bodies = JArray.object()
  JArray.addStr(bodies, "3BA")
  JArray.addStr(bodies, "3BBB")
  JArray.addStr(bodies, "CBBE")
  int n = JArray.count(bodies)
  int i = 0
  string node

  While i < n
    node = JArray.getStr(bodies, i)
    If NetImmerse.HasNode(npc, node, false)
      return node
    EndIf
    i += 1
  EndWhile

  return ""
EndFunction

If you want to add another body check, it's just a matter of adding another addStr() line with the node name you found in Nifskope.

For example:

JArray.addStr(bodies, "UNP5thAnniversaryVersion")

Hands

Here's a quite dirty sample I left like this just to show you how even hand nodes may have many different kind of names.

I'm quite sure you are thinking about better ways to do this function. And you are right.

string Function GetHandsNode(Actor npc)
  If NetImmerse.HasNode(npc, "Hands", false)
    return "Hands"
  ElseIf NetImmerse.HasNode(npc, "HIMBO - Hands", false)
    return "HIMBO - Hands"
  EndIf

  return ""
EndFunction

Beware about this one.

Warning

Hands nodes disappear when an Actor is completely naked.

In fact, this was the thing that lead me to solving the "Pizza Hands Syndrome" once for all.

But I'll talk about that in my next article.

Last article I promised to tell you how to change head textures, and here it is.

I adapted the method used by Wet Function Redux author to make it easier to read and work with.
This method was made to add compatibility with High Poly Head, but it solved compatibilty issues with many other types of heads.

string Function GetHeadNode(Actor aAct)
  ActorBase ab = aAct.GetActorBase()
  int i = ab.GetNumHeadParts()
  string headNode
  While i > 0
    i -= 1
    headNode = ab.GetNthHeadPart(i).GetPartName()
    If StringUtil.Find(headNode, "Head") >= 0
      return headNode
    EndIf
  endWhile
  return ""
EndFunction

As you can see, this method is way more elegant that the ones I discovered.

That's because there's such a thing as GetNumHeadParts(), GetNthHeadPart() and HeadPart.GetPartName().

If there were similar functions for hands and bodies, and if bodies followed a sort of unified naming convention, doing something like this would be possible.

But if you happen to know a better way to get nodes than mine, please let us know.
It would be awesome to have an easy way to access all body and hands nodes.

Anyway, this is all you have to do to change face (head) textures:

NiOverride.AddNodeOverrideTextureSet(ref, isFemale, GetHeadNode(ref), 6, -1, texture, true)

I trust at this point you should be able to use AddNodeOverrideString by yourself, no?

Wrapping up

Before we go, there's one last thing you need to know about node overrides:

Warning

Since body node overrides depend on which armor you got equipped, they reset as soon as you unequip it.
It doesn't matter if you set overrides to be persistent... and you better not do that, or you will bloat players' save games pretty fast.

Notice how this only applies for the all the general nodes I talked about in this article.
Node Override Layers will totally persist because they are entities separated from all this armor stuff.


  1. If you don't know where the 9 and 0 came out from, read this. ↩︎

  2. Unless you are using a mod that gives them erections on command, I suppose. ↩︎

  3. You could also use plain Papyrus arrays, but I prefer JContainers ones because Papyrus is a toy language and its arrays are mostly useless. ↩︎