The final version of this guide can be found here!
This guide was created after reading this one and being left with a bunch of question marks. The good people on the modding discord have been extremely helpful and clarified many questions. To get a deeper understanding, refer to the initial guide and follow the linked resources.
Assumed skill level: You should be able to find your way around WolvenKit, but I aim to keep this as noob-friendly as possible.
You will find the framework's official documentation here.
Parts of this guide
- Getting the right files and setting up the folder structure
- Explanation of each file for the purpose of this guide
ℹThis section contains a diagram with how the files interact! - Putting the right content into the files, hooking them up the way it's shown in the diagram
- Adding appearances
Perquisite | |
---|---|
Necessary mods | TweakXl, ArchiveXl, and Red4ext. |
WolvenKit | WolvenKit Nightly |
⚠This tutorial has been created with the bleeding-edge WolvenKit Nightly. I recommend that you grab at least 2022-11-02, unless yours is more recent — it has no breaking bugs, and all files will get copied reliably.
If you're using an older version of WolvenKit, the folder structure for ArchiveXL items will not match the one assumed below, and maybe not all files get copied to "packed".
👉 TL;DR: If you can't be arsed doing this by yourself, find a template project with one working item (female rigged) here.
This part of the guide deals with setting up the files and putting them in the right place. After that, there'll be an explanation of what they do, and finally, a step-by-step guide of filling them with content.
We'll assume that your mod is named my_shirt
and will live in the folder archive\tutorial
:
tutorial\my_shirt
Create a subfolder with the name of ops
(for 'operations'). Here we'll put those files that organize how the items correspond to the appearances.
You should end up with the following file structure:
archive
- base
- tutorial
- myshirt
- ops
ℹIt is good practice to have a folder for your modded stuff directly under archive
. That way, base
is reserved for the non-modded base game items.
As for an explanation which file does what, see the next section "What do these files do".
Now, add the following files to your project and move them to tutorial\my_shirt
:
base\gameplay\items\equipment\underwear\player_underwear_item.ent
base\gameplay\items\equipment\underwear\appearances\player_underwear_item_appearances.app
base\characters\garment\player_equipment\torso\t1_080_pwa_tank__judy.ent
(any file from this folder will do)- your mesh (I'll use
base\characters\garment\gang_monk\torso\t2_135_jacket__monk_shirt\t2_135_wa_jacket__monk_shirt.mesh
)
and the operative files (these go into the subfolder tutorial\ops
):
base\gameplay\factories\items\clothing.csv
base\localization\en-us\onscreens\onscreens.json
Rename them as follows:
file name | new file name |
---|---|
player_underwear_item.ent |
rootentity.ent |
player_underwear_appearances.app |
appearance.app |
t1_080_pwa_tank__judy.ent |
mesh_entity.ent |
t2_135_wa_jacket__monk_shirt.mesh |
my_mesh.mesh |
file name | new file name |
---|---|
clothing.csv |
my_cool_new_items.csv |
onscreens.json |
translation_strings.json |
⚠Do not edit those files outside of WolvenKit!
If you want to do that, you need to export them to json first (yes, even the json).
❗❗❗ Whatever you do, do not let Microsoft Excel touch the clothing.csv.
It is good practice to keep local copies of everything that you change (=> custompathing
) instead of overwriting files under base
. This makes sure that no other mods will overwrite your changes.
ℹ Only keep files under base
if you are okay with them being overwritten!
Create a new file by using WolvenKit's toolbar button.
- Select "ArchiveXL" on the left. This file will later go into
gamedir\archive\mods
.
Call ityourModName.archive.xl
, so that it'll be directly belowyourmodname.archive
. - Select "ArchiveXL" on the left. This file will later go into
r6\tweaks
.
Call ityourModName.yaml
.
⚠As of today (October 30 2022), WolvenKit can't edit the archive.xl
file. You'll have to use a text editor such as Notepad++.
tutorial
myshirt
- appearance.app
- mesh_entity.ent
- my_mesh.mesh
- rootentity.ent
ops
- my_cool_new_items.csv
- translation_strings.json
resources << from WolvenKit-8.7.1-nightly.2022-11-01
- yourModName.archive.xl
- yourModName.yaml
ℹ Before WolvenKit Nightly 2022-11-01, yourModName.yaml
will be located in the folder ArchiveXL
. I recommend updating.
👉 If you plan on adding more than one clothing item, I recommend keeping the translation_strings.json
in the clothing item's subfolder — that way, you can have multiple files for multiple items, rather than have everything in one.
-
Open the file
translation_strings.json
in WolvenKit.
Expand the arrayroot
and then the arrayentries
. Delete all entries but one. -
Open the file
my_cool_new_items.csv
in WolvenKit.
IncompiledData
, delete all entries but one. Indata
, delete everything - these will get autogenerated. -
Open the file
rootentity.ent
.Expand the list
appearances
. Delete all entries but the first (most likelydefault
). -
Open the file
appearance.app
.
Expand the listappearances
. Delete all entries butdefault
. -
Open the file
mesh_entity.ent
SelectresolvedDependencies
and delete all the entries. (We don't need Judy's top anymore.) -
Make a back-up copy of your mesh, then open it.
-
Expand the list
materials
. Open the appearancedefault
and check which material is linked in thechunkMaterials
array. -
Expand
localMaterialBuffer.materials
. Delete all entries that aren't used indefault
.
ℹ Some meshes don't havelocalMaterialBuffer
— look forpreloadLocalMaterialInstances instead
-
Expand
materialEntries
. Delete all entries that you also removed fromlocalMaterialBuffer
.
👉 You should be left with 1-3 materials. -
Now we need to adjust the indices.
⚠If you make any mistakes here, the wrong material will be loaded.Select the first
CMeshMaterialEntry
inmaterialEntries
and check the propertyindex
— it needs to be0
. -
Browse through each entry that is still in the list and make sure that the index is sequential.
ℹ You can see in the list which index each item needs to have:
-
✅ Now is a good time for a backup.
Here is a diagram of how the files connect to each other.
ℹ If you are renaming or moving files, you might want to refer to this diagram. It's what I do.
- As you can see, there are two entry points, the yaml and the archive.xl.
- The yaml and the csv together load the rootentity, which is responsible for displaying the correct mesh.
ℹ You need to touch it only once, unless you want to add new files.
The factory connects yourModName.yml
via entityName
to the corresponding rootEntity.ent
.
When reading yourModName.yml
(explained right after this one), the game will find entries like this:
Items.my_shirt:
$base: Items.GenericFootClothing
entityName: my_shirt << you set this field
appearanceName: my_shirt_
displayName: my_shirt_name
When adding the new items, the entries in the factory will be filtered by entityName
for a match in the first field:
{
0: my_shirt << as corresponding to entityName in appearance.app
1: tutorial\myshirt\rootentity.ent << this file will be used to resolve the appearances
},
{
0: my_boots << this does not match
1: tutorial\myshirt\rootentity.ent << so this file won't matter here
}
… and use rootentity.ent
to look up an appearance by the name of my_shirt_
.
This file controls the adding of items to the game. You will touch it every time you add another colour variant or additional items.
ℹ You need to touch this file every time you add a colour variant or a new item.
An entry looks like this:
Items.my_shirt: << name of the item in game (for spawn code)
$base: Items.GenericInnerChestClothing << select the type of clothing you want
entityName: my_shirt << maps to my_cool_new_items.csv by entityName => data[x][0]
appearanceName: my_shirt_ << points to rootentity.ent. The trailing _ is on purpose!
displayName: my_shirt_name << points to translation_strings.json
localizedDescription: my_shirt_desc << points to translation_strings.json
quality: Quality.Legendary << we don't want the cheap garbage, do we now
appearanceSuffixes: [] << See the section "suffixes" below for an explanation
This will let you add the item via Game.AddToInventory('Items.my_shirt')
.
Three mappings take place here:
entityName
: Basically, the game will look throughmy_cool_new_items.csv
until it finds an array where the value for [0] (the first entry) is identical to this key. It will then use the file specified in [1] (the second entry) to look up theappearanceName
.appearanceName
: In the entity specified via csv, it will look for an appearance by this name.
ℹ The name will only be considered up to the first suffix - that is, everything before the & will be ignored.displayName
/localizedDescription
: In thetranslation_strings.json
, find an array where the value for [3] (the last entry) is identical to this key. Then, check which gender V has, and display eitherfemaleVariant
ormaleVariant
.
$base
defines which type of clothing to use. All those types have different properties (e.g. on which slot they are), and they inherit properties from their parent template, which can cause problems (see "Suffixes, and whether you need them" below for more detail).
The following types of clothing exist:
- Items.GenericHeadClothing
- Items.GenericFaceClothing
- Items.GenericOuterChestClothing
- Items.GenericInnerChestClothing
- Items.GenericLegClothing
- Items.GenericFootClothing
⚠When editing this file, please keep in mind that indent is important! The first line of each block must not have spaces, the following lines must have the same amount of spaces.
This file tells the game to load the factory (my_cool_new_items.csv
) and the localization file (translation_strings.json
).
ℹ You need to touch it only once, unless you want to add new files.
As for the content, see the section "Setting up the files" below.
This is the localization file which tells the game which texts to display.
ℹ You need to touch this file every time you add a new text string.
An entry will look like this:
femaleVariant: My shirt - Babydoll
maleVariant: My shirt - Sleeveless
primaryKey: 0
secondaryKey: my_shirt_name
The value under secondaryKey
must match the entry in yourModName.yml
, or you'll just see an empty string.
⚠If you don't need a male-specific translation, you can leave it blank — by default, femaleVariant
will be used.
This file defines which components should be loaded - that's why you should copy one instead of creating from scratch.
ℹ You need to touch this file every time you add a colour variant.
For our purposes, this is a glorified lookup map, translating between the key appearanceName
in yourModName.yaml
, a specified app file, and an appearance as specified in that file:
yourModName.yaml
$base: Items.GenericInnerChestClothing
entityName: my_shirt
appearanceName: my_shirt_
knows to look in my_cool_new_items.csv
for an entry matching the entity name, then open the corresponding app file specified there, and find the appearance by the name of appearanceName
.
An entry will look like this:
appearanceName: my_shirt
appearanceResource: DepotPath: tutorial\my_shirt\appearance.app
Flags: Default
name: my_shirt_&Suffixes
For an explanation of the '&suffixes' part, see the section below.
ℹIf you do not need Suffixes (which includes not knowing what you would want them for), you should leave them out.
In that case, make very sure that your .yaml contains appearanceSuffixes: []
in each entry.
For our purposes, this is just a collection of components.
ℹOnce you've set this up, you won't have to touch this file again - it's on a once-per-mesh basis.
An entry looks like this:
components: [
0: Component {…} << ignore this
1: entGarmentSkinnedMeshComponent { << the component loading our custom mesh
mesh:
DepotPath: tutorial\my_shirt\my_mesh.mesh << path to your mesh
Flags: Default << leave this alone
name: my_shirt << see below
}
]
The name will be used in appearance.app
's materialOverride array (see below)
❓ Why this file?
You don't strictly need it, as you could define the components array in the individual appearances in the appearance.app
. However, in the interest of not repeating ourselves, we bundle everything here. For example, if you re-name your mesh, you'll have to touch one file, rather than 25 different appearances in an array!
Contains a list of appearances as mapped by rootentity.ent
. It will indicate which mesh to display by loading mesh_entity.ent
, and overriding appearances.
ℹYou will touch this file every time you add a colour variant.
An entry will look as follows:
appearances:
handle:appearanceAppearanceDefinition: [
{
components: [] << replaced by mesh_entity.ent
name: my_shirt << this maps to the field 'appearanceName' in rootentity.ent
partsOverrides: appearanceAppearancePartOverrides[]: [{
partResource: tutorial\my_shirt\mesh_entity.ent
componentOverrides: [{
componentName: my_shirt << corresponds to the component's name in mesh_entity.ent, see above
mesh_appearance: colourset_01 << corresponds to the component's appearance in my_mesh.mesh
}]
}]
partsValues: appearanceAppearancePart[] = [{
resource: tutorial\my_shirt\mesh_entity.ent << which entity file to load?
}]
}
]
partsValues
will define what entity files to load (as a list of components), while partsOverrides
tells the mesh which appearance to use.
You probably know this, but since I'm already writing a guide, I figured I might as well be thorough.
The mesh file is the actual game object, which is made out of vertices, edges and faces.
It also holds the information on how the mesh deforms with the rig - without this, V's rig would move and the mesh would stay in place. This information is in the weights — different vertices are assigned to vertex groups which correspond to the name of the rig's bone (such as RightUpLeg
or LeftLegUp
) , and will then move when the bone does.
👉How much a vertex moves will be determined via vertex weights, which you can change in Blender's weight paint mode. Everyone I've ever talked to hates these things, so if you happen to be good at them and enjoy the process, please get in touch, senpai. ~manavortex
Suffixes tell the game which appearance to load under certain circumstances. Which ones will be considered depends on appearanceSuffixes: [ … ]
in the .yaml file.
⚠Your item might inherit the suffix setup from the component you specify it as. In the example of Items.GenericHeadClothing
, that will be
appearanceSuffixes: [ itemsFactoryAppearanceSuffix.Gender, itemsFactoryAppearanceSuffix.Camera ]
A mesh will first look for an appearance without any suffixes at all, and then always try to load the most specific appearance. In the example above, if you give the name of my_shirt_
, it will append the suffixes and (for a female V in third person camera mode) try to find my_shirt_&Female&TPP
.
my_shirt_
, will be loaded.
my_shirt_&Female
will be ignored.
ℹThis can be the reason why your item is invisible!! You can and should disable the suffixes if you don't need them.
To do so, add an empty array to the yaml entry:
appearanceSuffixes: []
For clothing items, the following suffixes are relevant:
Suffix | Explanation |
---|---|
itemsFactoryAppearanceSuffix.Gender |
This item is gendered When resolving the appearance name via rootentity.ent , the game will look for appearanceName&Female and appearanceName&Male . |
itemsFactoryAppearanceSuffix.Camera |
This item has special rules for first and third person camera When resolving the appearance name via rootentity.ent , the game will look for appearanceName&FPP and appearanceName&TPP . |
itemsFactoryAppearanceSuffix.Partial |
If the current item has hide_T1part part and slot OuterChest is not hidden, will search rootentity.ent for&Full or &Part |
itemsFactoryAppearanceSuffix.HairType |
Defines how your item will look if a certain hair type is loaded (e.g., hide the back half of a bandana for long hair). When resolving the appearance name via rootentity.ent , the game will look for &Short , &Long , &Dreads , &Buzz , &Bald |
For a more in-depth list, see here.
ℹ Unless otherwise specified, it'll be assumed that you edit these files in WolvenKit.
Put the following content:
factories:
- tutorial\ops\my_cool_new_items.csv
localization:
onscreens:
en-us: tutorial\ops\translation_strings.json
Save and close the file. You do not need to touch this again unless you want to add more files or change paths.
Find the array root
, then find the array entries
. (After the optional step in the setup, it should contain only one entry.)
Change it as follows:
localizationPersistenceOnScreenEntry - []
femaleVariant: My shirt (unisex)
maleVariant:
secondaryKey: my_shirt_name
Duplicate the item by right-clicking on it. Change the new item as follows:
localizationPersistenceOnScreenEntry - []
femaleVariant: A generic T-shirt. Can be worn by pretty much everyone.
maleVariant:
secondaryKey: my_shirt_desc
ℹ The second part is what you do every time you want to add a new text, such as names for colour variants or different descriptions.
-
Find the list
compiledData
. It should have only one entry after you cleaned up the files. -
Select the item and duplicate it, then select your new entry. (
arrayString
) -
It should have three (3) items. Set the values as follows:
0: my_shirt 1: tutorial\myshirt\rootentity.ent 2: true
ℹ The list data
will get overwritten with the values from compiledData
.
Find the first component of the type entGarmentSkinnedMeshComponent
. Set the following values:
mesh: DepotPath: tutorial\my_shirt\my_mesh.mesh << path to your mesh
Flags: Default << leave this alone
name: my_shirt << this corresponds to the appearanceOverride in appearance.app
Remember the value for name
, as you'll use it in your rootentity.ent
a lot.
⚠Since November 1st, 2022, WolvenKit can edit yaml files. With older versions, please use a text editor.
Create the first entry in yourModName.yaml
, so that you can spawn it via Game.AddToInventory('Items.my_shirt', 1)
. You can copy and paste the part below.
The total file content should be:
Items.my_shirt:
$base: Items.GenericInnerChestClothing
entityName: my_shirt
appearanceName: my_shirt_
displayName: my_shirt_name
localizedDescription: my_shirt_desc
appearanceSuffixes: []
In wKit:
This is a lookup table between the key appearanceName
in the yaml. It specifies which appearance (appearanceName
) to look up in which file (appearanceResource/DepotPath
).
-
Find the array "appearances" - nothing else here interests us at all. There should be only one entry left.
-
Select it and put the following details:
appearanceName: my_shirt << as corresponding to the appearance in the mesh itself appearanceResource: DepotPath: tutorial\my_shirt\appearance.app << path to your app file Flags: Default name: my_shirt_ << as corresponding to appearanceName in the *.yaml
This connects your entry Items.my_shirt
from yourModName.yaml
via name
with the file specified in appearanceResource
, where it will then load the appearance entry corresponding to appearanceName
. (Which we are about to create.)
-
Find the array
appearances
- nothing else here interests us at all. -
Delete all entries but
default
-
Expand the entry
default
-
Find the array
partsValues
.-
Delete all entries.
-
Create a new entry. Set the following value:
resource
:tutorial\my_shirt\mesh_entity.ent
ℹ This file specifies which components to load.
-
-
Find the array
partsOverrides
.-
Delete all entries.
-
Create a new entry. Set the following value:
DepotPath
:tutorial\my_shirt\mesh_entity.ent
-
Select the array
componentsOverride
and create a new item. Set the following values:componentName
:my_shirt
(as specified in themesh_entity.ent
)meshAppearance
:default
ℹ This will make sure that the component
my_shirt
will be displayed with its appearancedefault
, as specified in the mesh.
-
✅ Regardless of whether or not this actually works, this is a great moment for a back-up!
In WolvenKit, click the "Install" button. There will now be a folder "packed" in your mod directory, right next to the folder "source".
Check if it includes the following file: <yourModDir>\packed\r6\tweaks\yourModName.yaml
. If it is missing, you need to copy the <yourModDir>\source\tweaks
directory over.
Press "Install and Launch" in WolvenKit. This will do the following things:
- Copy all supported file entries from
source
to their destination underpacked
, overwriting older files - Pack an archive in
packed\mod\archive
, overwriting the last version - Copy all files under
packed
into your game directory, again overwriting older files - Launch the game.
You can now spawn and equip your item by running the following command (as specified in your yaml):
Game.AddToInventory("Items.my_shirt")
You should now see your item. If not, consult the section Troubleshooting below, or retrace your steps and make sure that everything works before proceeding to the step below.
⚠Before you add an appearance, make sure that your item is loading up correctly. If you have to debug, you will have to look through every appearance you made!
To add one, you will have to touch the following files:
-
*.yaml: Adding an entry
-
appearance.app: Adding a mapping between rootentity and mesh's appearance
-
rootentity.ent: Adding a mapping between yaml's appearance and app's appearance
-
*.mesh:
- Adding a MeshMaterialEntry
- Adding a MaterialInstance
- Adding a material
- Connecting those things
-
Duplicate the entire appearance block for an already working item.
⚠Mind the indent! -
Change the first line to a unique name like
Items.my_shirt_blackred
-
Set the new appearance name for the
rootentity.ent
appearanceName: my_shirt_blackred_
-
For lookups in your translation file (
translation_strings.json
): Change the values ofdisplayName
andlocalizedDescription
to the corresponding secondary keys in the json file.
This is optional.displayName: my_shirt_blackred_name localizedDescription: my_shirt_blackred_description
ℹIf you make any mistakes here, the worst that happens is an empty string.
Example:
yaml:displayName: my_shirt_nameblackred_name
json:localizationPersistenceOnScreenEntry - [] femaleVariant: my item - now in black and red maleVariant: secondaryKey: my_shirt_name_blackred_name
The total entry should look like this:
Items.my_shirt_blackred:
$base: Items.GenericInnerChestClothing
entityName: my_shirt
appearanceName: my_shirt_blackred_
displayName: my_shirt_blackred_name
localizedDescription: my_shirt_blackred_description
appearanceSuffixes: []
Expand the list appearances
and duplicate your already working entry.
Change the following fields:
appearanceName
=> everything before the & must match appearanceName
in your *.yaml
name
=> must match the name you're going to put in your app.app
Example:
old:
appearanceName: my_shirt
name: my_shirt_&TPP
new:
appearanceName: my_shirt_blackred
name: my_shirt_blackred_&TPP
ℹ You do not need to change the appearanceResource
.
Duplicate your already working entry and name it the way you've just defined as appearanceName
in the rootentity.ent
.
ℹ If you're missing any of the items below, go back to "Edit the appearance.app" above. If everything is beyond broken, restore the file from one of your backups.
- Open the .app file and expand the list
appearances
. - Duplicate an item and select the new one.
- In the new appearance, find the array
partsOverrides
and expand it. - Select the item inside.
- Find and expand the Array
appearanceAppearancePartOverrides
and expand it. - Select the first item.
- Open the array
componentsOverride
and select the first item. - Change the value of
meshAppearance
to the name of your new appearance in the mesh:
componentName: my_shirt << no need to change this
mesh_appearance: black_red << corresponds to meshMeshAppearance.name in my_mesh.mesh
ℹ You can leave partsValues
alone - this just points at the file that loads the mesh, and you've already set it up above when setting up the file.
This tutorial assumes you already know how to recolour an item. Quick reminder about the mlsetup:
- Export it to json
- put the json file in the same directory as the original .mlsetup
- edit the
mlsetup.json
with the MLSetupBuilder (there's a WolvenKit plugin now) - Save it under the new name.
Now we're adding the new appearances:
-
Find the array
materials
and open it.-
Duplicate the last entry. (Yes, use the last one, please, it's important for step 3).
-
Select the new last entry
-
Set the following values:
name: mat_black_red <<< will be used by meshMeshAppearance in appearances[] index: <index of item in array>
If you duplicated the last material, you can just increase it by one.
-
-
Find the array
localMaterialBuffer
and open it- Duplicate any entry with an mlsetup (You will see an entry
MultilayerSetup
undervalues
) - Drag it to the last position of the array (that's important, because the materials entries match by numeric index)
- Select the new item, open
values
, and selectMultilayerSetup
. - Set
baseMaterial/DepotPath
to the.mlsetup
file that you want.,
- Duplicate any entry with an mlsetup (You will see an entry
-
Find the array
appearances
and open it.-
Duplicate any material.
-
Change the name to the one you've defined in the
appearance.app
above (in this case:black_red
):name: black_red
-
Select the array
chunkMaterials
and change the entries in the right-hand panel to use the material you defined in step 1.
-
Now, log into the game and spawn the item variant. The name is in the yaml file, in this case
Game.AddToInventory('Items.my_shirt_blackred')
Okay, now you've added something! But it doesn't have a preview icon yet - you'll have to add this manually.
For this purpose, you'll have to edit an image — for this, I recommend paint.net, (free)
⚠You can not use Photoshop for the final step. Or rather, you can, but the transparency will be botched. ⚠
Cyberpunk uses xbm as format for its textures. These textures are then mapped (divided into slices) by inkatlas files. The individual slots can then be used by the game for pretty much everything from UI elements to phone call icons — and image previews.
First of all, download the template archive (kindly provided by Apart). This includes the following files:
Template | Size of slot image |
---|---|
5_outfits | 160x320 (x5) |
5_weapons | 360x120 (x5) |
40_items_inkatlas_template | 160x160 (x40) |
As for how to take image previews, refer to this guide, section "Making the icon". This guide assumes that you have a bunch of ready-made icons lying around.
Select 40_items_inkatlas_template and copy the .inkatlas and the .xbm tutorial\ops
. I'll rename them to preview_icons
, future me will be grateful:
tutorial
ops
- my_cool_new_items.csv
- translation_strings.json
- preview_icons.inkatlas <<<
- preview_icons.xbm <<<
Open 40_item_template.pdn
in paint.net and put all your icons in. Hide the background layer once you're done, and save it as png under
<yourModDirectory>\raw\tutorial\ops\preview_icons.xbm
ℹYou can also export preview_icons.xbm
via WolvenKit, and the resulting preview_icons.png
in paint.net!
Once you're done, import it back. Use the following settings:
You can now open preview_images.xbm
in WKit, it should have your items.
- Open the file in WolvenKit.
- Open the list
slots
. - For the first two
inkTextureSlot
items, set the value forDepotPath
to the relative path of your xbm (tutorial\ops\preview_icons.xbm
):
- Save the file. Currently (October 20022), WKit doesn't yet auto-update, so you need to close and re-open your inkatlas.
- You now have a tab "PartMapping". You can now see which texture corresponds to which slot:
We add three more lines to the item:
Items.my_shirt_blackred:
$base: Items.GenericInnerChestClothing
entityName: my_shirt
appearanceName: my_shirt_blackred_
displayName: my_shirt_blackred_name
localizedDescription: my_shirt_blackred_description
appearanceSuffixes: []
icon:
atlasResourcePath: tutorial\ops\preview_icons.inkatlas
atlasPartName: slot_16
That's it! Time to test!
⚠ Again, please note that indent is crucial here, as it determines the node structure. The first line needs to have an indent of 0, the lines from $base
to icon
need to have two spaces, and the lines atlasResourcePath
and atlasPartName
need to have four.
This section will detail how to add an Atelier store with your items.
⚠You need to install the VirtualAtelier mod for this.
First of all, download the template archive (kindly provided by Apart) and find the folder virtual_atelier_inkatlas_icon_template.
atelier_icon_template.inkatlas << map for the game
atelier_icon_template.png << 200x200px image for a final slot
atelier_icon_template.xbm << game texture
virtual_atelier_png_to_xbm_import_settings.png << image, also embedded here
Put the .inkatlas and .xbm into your ops folder under tutorial\ops
and rename them to atelier_icon
:
tutorial
ops
- my_cool_new_items.csv
- translation_strings.json
- preview_icons.inkatlas
- preview_icons.xbm
- atelier_icon.inkatlas <<<
- atelier_icon.xbm <<<
Now, create your icon. The process is the same as in the section "Preview images". The resulting slot will be named slot_01
.
- Visit this website and fill out the information:
Field | Content |
---|---|
Store ID (characters only, w/o spaces, '-', '_' and etc.) | MyTutorialAtelierStore |
Store Name | My Tutorial Atelier Store |
Atlas Resource | tutorial/ops/atelier_icon.inkatlas ⚠Make sure to replace all backward slashes with forward slashes here! |
Texture Part | slot_01 |
- Now, add your item.
Field | Content |
---|---|
TweakDBID | Items.my_shirt |
Price | Whatever price you want, 0 means that it's free |
Quality | Are we settling for anything but legendary here? |
Ignore "Icon path" and "description", we have these in the item itself.
- Click "Add Item". Repeat the process with as many items as you want.
- Click "Generate".
Move the atelier file from your download folder to WolvenKit's resources
folder:
resources
- MyTutorialAtelierStore-atelier-store.reds << new file
- yourModName.archive.xl
- yourModName.yaml
Now, it's time to test! Install the mod, then start Cyberpunk via start menu shortcut.
⚠As of today (3rd of November 2022), starting Cyberpunk via WolvenKit will not generate your atelier store. You need to first install the mod, then start the game via start menu or GOG launcher.
Something went wrong with your json file:
Check the following places:
yourmodname.archive.xl
:- Does the key
localization - onscreens - en-us
exist? - Is the indentation correct, as shown in the picture?
- Does it point at the correct file (
tutorial\ops\translation_strings.json
), or did you rename or move it? - Did you make any typos?
- Does the key
yourModName.yaml:
- Is the spelling for the key you defined after
displayName
andlocalizedDescription
identical to the one in the json file?
- Is the spelling for the key you defined after
translation_strings.json
:- Is the spelling of the key defined in yaml's
displayName
andlocalizedDescription
identical? - Did you set the femaleVariant (default)?
- Is the spelling of the key defined in yaml's
That's relatively easy to fix — the error is somewhere in the first part of the chain:
Check the following places:
yourmodname.archive.xl
:- Is the indentation correct, as shown in the picture?
- Does the value for
entityName
have a corresponding entry in the factory (my_cool_new_items.csv
)? - Does it point at the correct rootentity(
tutorial\myshirt\rootentity.ent
), or did you rename or move it? - Did you make any typos?
rootentity.ent:
- Is the spelling for the key you defined after
displayName
andlocalizedDescription
identical to the one in the json file? - Are you using any suffixes? Are you using the correct ones? Try creating a fall-back entry without any suffixes.
- Is the spelling for the key you defined after
Congratulations, you've made it into the right half of the diagram! The error will be somewhere here:
👉 If you set your mesh_entity.ent
to point at a vanilla mesh, you can rule out your custom mesh and .mlsetup as a source of errors. Original game meshes will always have a working default appearance and will thus always be displayed!
That means the chain is working, but something isn't loaded correctly. That's good! Check the following files:
appearance.app
: Check thepartsValues
andpartsOverrides
entries. They need to point at themesh_entity.ent
, not at the mesh.mesh_entity.ent
: Does thecomponent
entry point to a valid mesh? Try it with a default mesh as detailed above.
If that works, then the problem is your mesh.
For more detailed error handling, check the sections below.
ℹ In the "Mesh Preview" tab of your mesh, you can "Generate Materials for Appearance". If the correct colours show up, you can at least rule out that the error is in the .*mesh or the *.mlsetup!
- Make sure that you have the same number of entries in
materialEntries
andlocalMaterialBuffer.materials
. - Go through the
CMaterialInstance
s inlocalMaterialBuffer.materials
.- Make sure that the files you're loading exist.
- Make sure that you don't load a mlmask under a key for an mlsetup or vice versa.
If none of that helps, I suggest
- doing a gdb export
- throwing away your mesh (don't close the WKit tab yet), falling back to the original one
- doing a gdb import
- replacing the arrays
appearances
,localMaterialBuffer.materials
andmaterialEntries
with those from your previous mesh.
Congratulations, this is about the easiest-to-resolve error that you could've had. Your mesh is loaded correctly, there is only a problem with the rendered material.
Check your mesh file:
- Check the connection between
appearance
,materialEntry
andlocalMaterial.CMaterialInstance
. Are the names correct? - Go through the
CMaterialInstance
s inlocalMaterialBuffer.materials
.- Make sure that the files you're loading exist.
- Make sure that you don't load a mlmask under a key for an mlsetup or vice versa.
Either an appearance is incorrectly selected, or it is incorrectly resolved. Check the following places for copy-paste/duplication mistakes:
yourModName.yaml - is the appearanceName
correct, or did you forget to change it?
rootentity.ent - does the name
corresponding to the field above point to the appearanceName
with the right name?
appearance.app - does the appearance's partOverride
set the correct appearance in the componentsOverride
?
Now, check the mesh file (close and re-open it to make everything refresh):
appearance - does it use the correctly named material?
materialEntries - is the index correct, or is it pointing at the index of the actually displayed material?
localMaterialBuffer - does the CMaterialInstance use the correct .mlsetup file?
Finally, check the .mlsetup: does it actually use different colours, or is it just a duplicate?
Here we go. This is the big one, and it's Not Fun. The error can be anywhere between the yaml and the mesh. You can rule out one of the files with the following question:
Does the glitching stop after <10 seconds?
If not: the appearance can't be resolved - ignore the mesh
If yes: the appearance is resolved, but can't be displayed - ignore the yaml
ℹIf the appearance is resolved, but not displayed (short glitch), the first thing you should do is to change the path in the mesh_entity.ent
to one of the game's default meshes. This will rule out errors on your part. (Yes, even if your mesh worked in another mod. No, I'm not speaking from experience, why do you ask?)
If the hint above doesn't solve it, proceed to troubleshoot in the same way as "My mesh has the wrong appearance!" above.
Time to restore your files one by one to the last working backup and restart from there.
Don't delete them, keep them in a different folder - you will be able to copy a lot of stuff over.
ℹBy right-clicking on a tab title, you can move it to a new document group for easier copying.
Good luck, soldier.