An item addition with dynamic appearances, and what you can do for this
Summary
Published: 29 Oct. 2023 by mana vortexLast documented update: Jul 05 2024 by mana vortex
This guide will cover a sub-case of Adding new itemsvia ArchiveXL (added in 1.13). Dynamic variants are both easier and more flexible. Unless you don't need different appearances, you will want to default to this approach.
TL;DR
In your root_entity:
Add the DynamicAppearance tag
Delete all but one entry from the appearances array.
Name it like your entityName in the yaml
Leave the appearanceName blank
In your .app:
Delete all but one entry from the appearances array
Name it like your entityName in the yaml
Delete all components
Point it to your mesh_entity
In your mesh_entity:
To enable substitution in mesh depot paths, make sure they start with *
Put all attributes that ArchiveXL should switch out in the paths in {}
You define an appearance as dynamic by adding the DynamicAppearance tag to the visual tags in its root entity.
If you don't know what that means yet, read on — it will hopefully become clear soon.
How is this better than the old approach?
TL;DR: It just is, source: trust me bro. Proceed to the next section.
Why dynamic appearances are superior
With vanilla item additions, you need one entry in the root entity per suffix. This gets out of hand quickly. When making stockings, there are four feet states (flat, flat_shoes, lifted and high_heels), and two body genders (Male and Female) . That leads to 4x2 entries for a single item.
For 15 appearances (colour variants) per mesh, I (manavortex) ended up with
120 entries in the root entity (4*15 per body gender)
120 entries in the .app file, (4*15 per body gender)
six mesh_entity files (flat, lifted, and heels for each body gender. I used the same for flat and flat_shoes, or I'd have ended up with eight.)
The most frustrating part was that everything was just duplication. Each set of entries in the .app file would only differ by name (_pwa and _pma to select it from the root entity), and the mesh entity path in partValues. Everything else was virtually identical, but I had to copy-paste and maintain 120 entries.
I cried to psiberx, who went and made the problem go away.
Dynamic variants put the logic into the mesh entity file. Instead of defining appearances with suffixes, I can conditionally define which component gets loaded, and ArchiveXL does the rest.
This guide contains the minimal amount of fluff and will link background information rather than giving it. Any links will tell you what you're supposed to read.
For that reason, you shouldn't skip or skim unless the section tells you that it's optional.
That being said, make sure to check the Troubleshooting section if you run into issues, and to run File Validation ->On the entire projectto check for common mistake.
Step 0: Run the generator
Archived lore: the example project
This guide assumes that you have access to the prepared example project, so go and grab it.
Download it and extract the files to your project's root folder, so that the source directory merges with the existing one.
If you haven't, go and create a Wolvenkit Project. I'll name mine my_archive_xl_item,
In the File -> Add files... menu, select ArchiveXL item
Fill out the wizard with your item's information. For the example project, I'll create a t-shirt:
The fields, Mason! What do they mean?
Item Type
This determines the equipment type of your item, which slot you equip it in. It also determines the base game item for the generator.
Item Name
Your item's unique name. This will be used to generate spawn codes and translation entries (you can change them later).
Item Subtype
Allows fine-tuning of the Item Type (e.g. instead of a generic head item, you can pick a mask)
EquipmentEx slot
EquipmentEx decides what slot to equip your item in based on its type and subtype, but you can override this - for example, a tight netrunner suit can be worn on the innermost layer. This also influences item layering via Garment Support (which item is worn above/below)
In theory, this allows fine-tuning of garment support (e.g. by defining a coat as XLarge). In praxis, you're better-off relying on EquipmentEx for this.
This will add all of the template item's materials to your mod and custompath them. Takes at least a few extra seconds. Instead of doing this, you can also open the .mesh files and select Materials -> Add dependencies.
Item variants
This field lets you define colour variants for your item. You can easily set this up via dynamic appearances later, so go nuts, you crazy diamond.
Use two variant fields
Use this if your item has more than one variant (for example, a t-shirt colour and a decal)
Secondary variants
Here you can enter values for your secondary variant. In the example, I'll be using the decal options - galaxy, witcher, and samurai.
0.1: Import the icons
Import the auto-generated .png icon files (Import Tool -> Import All). They are just dummy icons, but they will help telling apart your shirts while you work on them.
You can now delete the .png files.
Check Your own inventory preview icons for a guide on how to create the final thing. Most people do this at the end of their project, so you don't have to do it now.
Depending on the options you picked, your project will now look similar to this:
Step 1: Connecting the decal (and understanding variants)
Before starting this section, create a copy of your mesh_entity.ent now (press the ctrl-key and drag it on itself), as you need the original file for one of the alternative approaches.
This section will teach you how to make use of the variant to switch out item parts via .yaml. As a reminder, this is our yaml:
DynamicAppearances makes everything after the ! available in the mesh entity under the key variant. By adding +, you can split the variant into parts. Expand the box below to see more examples, because this is where the magic lives.
Examples
raw variant
variant
variant.1
variant.2
$(base_color)+$(secondary)
black+samurai
black
samurai
$(base_color)$(secondary)
blacksamurai
blacksamurai
-
$(base_color)+$(foo)
black+
black
-
By default, our _mesh.ent looks like this (because the generator re-uses CDPR's file structure)
As you can see, the paths are already dynamic - the m or w has been replaced with {gender}. This makes sure that our mod will display the right file based on your V's body gender.
This is incredibly powerful — for example, by using {body}, you make ArchiveXL pick the correct refit per body mod.
ArchiveXL: Suffixes and Substitutions contains a full list of suffixes and substitutions, but do finish this guide and its exercises before playing around even further!
Now, let's get that decal connected.
Select the first deactivated component, and turn it on by checking a few of the boxes (e.g. the first 3).
Select the second and third deactivated component, and delete them.
Based on the value of secondary (see the expandable above), we have the following values for variant.2:
galaxy
samurai
witcher
In the mesh depot path, replace samurai.mesh with {variant.2}.mesh
Change the meshAppearance to samurai (since the generator set that up for us)
Thanks to ArchiveXL's substitution, we only need one component to pick our choice from three .mesh files — based on the value for secondary in the yaml.
This approach is not recommended for anything user-editable. For details, see Exercise 1: Other options
Exercise 1: Other options
Dynamic mesh picking based on yaml params saves a lot of duplication, typos can lead to crashes — if you enter semurai instead of samurai, the game will try to find (for female V)
manavortex\equipment\torso_inner\my_custom_shirt\meshes\t1_079_pwa_tshirt__casual_dec_semurai.mesh
and then crash because it doesn't exist.
This is generally bad, so which options do we have to prevent it?
The boxes below contain suggestions and detail different ways to tackle the same problem with ArchiveXL. You can combine them or completely ignore them, as you want.
mesh_entity: One decal mesh, multiple appearances
This requires the least amount of changes in our project: you put all the appearances into the same .mesh file, and only switch the loaded texture via meshAppearance.
Unfortunately, CDPR used three different meshes, so you'd have to create the full decal on your own (check out the Adding decalsguide)
The result would look like this:
_app: Three decals, one appearance, partsOverrides
By slightly changing our .yaml, we create different appearances in the root.ent and the .app file:
The !$(base_color) will still arrive in our mesh_entity.ent as {variant}, but we no longer have a second field (no +).
We need to register our appearances in the root.ent :
Instead of a single appearance, we now have three. Still better than 9 (per colour) or 18 (per colour+body gender)!
This is what we kept the original mesh entity for, as we will use this in the .app file in the next step. Open it, and turn all disabled components visible:
If you were to spawn this t-shirt now, it would have all three decals. We don't want this. Luckily, we can use partsOverrides to hide things from the .app (but not show them, that's why we turned them all visible).
In the .app file,
Change the path under partsValues to mesh_entity_copy.ent
Duplicate the entire appearance two more times
Change the names to the same ones you used in the root_entity.ent
Now, create a partsOverrides, and then two componentOverrides inside. For every componentOverride, set the following values:
chunkMask to 0 (this will completely hide the component)
meshAppearance to an empty string (displays as None, this will make AXL ignore it)
componentName to the name of a component that you want to hide (you can copy them from the mesh_entity_copy.ent)
For every appearance, hide the other two decals.
An example of a real mod
I use both of these techniques in my University Outfit mod. Every mesh file contains several states of the same item, and I use partsOverrides to switch between them based on the yaml configuration.
For details, expand the box.
How University Outfit uses dynamic variants
Polo: Collar states
The mod supports two collar states on the polo - open and closed.
mesh
submeshes for "closed"
submeshes for "open"
torso
0,1,2
3,4,5
collar
0,1
2,3
tie
0,1
2,3
Polo: Sleeve lengths
You can pick three sleeve lengths for the polo: short, long, and gloved. The mesh chunks are set up as follows:
short: 0
long: 1, 2
gloved: 1, 3
(Yes, long and gloved share the same mesh for the part from shoulder to elbow, only the part below that is different).
So I ended up with six appearances in the _root.ent and .app:
On top of that, I am using ArchiveXL custom tags to display yet another collar when the sweatshirt is worn on top of it. For this, I'm also using the "open collar" tie, so I had to make sure that it fits both... I spent a lot of time re-fitting on this mod.
The diagram
Now let's look at what we just did and check the diagram. You'll see that the control files are almost identical to the vanilla variants, but that the rest of the files has gotten a lot more manageable:
And that's it! With this and the original guide, you should hopefully be able to add items to your heart's content!
Tools and utilities
Generating display names
I have written a Python script to auto-generate display names, you can find it on my github. If you don't know how to use this, check Running Python Scripts.