• If you have a mod, tool or prefab, please use the Resources section. Click Mods at the top of the forums.

XPath Modding Explanation Thread

This is a large amount of information in these posts. I'll be working on a full, properly formed tutorial as we get access to A17 and we can really make the xpath system shine. I've listed some examples here, and we'll be posting a ton more xpath samples over the coming weeks, as we port the SDX modlets over to use the native hooks.

By all means, begin posting your comments, questions, or requests for clarity.

Since we now know that xpath support will be built-into the vanilla base game, and discussions earlier were getting a bit confusing, I've decided to make a new thread to try to demystify xpath and what it'll mean for mods and modders going forward in A17. The information in this thread has been pieced together from forum and discord discussions. They may not be 100% accurate, but I will update this thread when we know the full implementation.

XPath is a way of adding, changing, or removing XML lines and nodes, without directly editing the XML files. It allows you to apply patches to the XML files without manually editing the vanilla XML files.

SDX has had partial support for this since its initial release, and a lot of the SDX Modlets are already written this way. We will be using some of the SDX's xpath as examples in this thread, but SDX is not required to do this in A17 and onwards.

I believe in using examples to explain concept, so in the next few posts, you'll see a mixture of explanation, along with sample xpath code.

The following Mod structure is expected for A17 and beyond:

Code:
Mods/
   <ModName>/
       Config/
       UIAtlases/ItemIconAtlas/
       ModInfo.xml

   <ModName2>/
       Config/
       ModInfo.xml
You will be able to have multiple mods loaded, and loading will occur as long as the ModInfo.xml exists. This is unchanged from what we've been doing doing with other alphas, with the exception of the Config folder.

This Config folder will support loading XML files, written using xpath, in the following folder structure:

Code:
Config/entityclasses.xml
Config/gamestages.xml
Config/items.xml
The files in the Config folder will not be a full copy of the vanilla file with your changes. Rather, it'll contain the changes you want done to the vanilla files. The files under the Config must match the vanilla file name. You cannot create an entityclasses2.xml file, and expect it to work. Any changes in the entityclasses.xml will have to be done in the same file. However, each mod can have its own entityclasses.xml.

During the game's initialization, it will perform the xpath merge in-memory only; no files will be actually be modified. This would allow us to remove mods we no longer want, without re-validating against steam, or previous copies of the xml. That's a big one. No more half merging of a mod, and not having it work, then trying to pull it back out.

What this means for us is that we'll be able to make a variety of smaller mods, which I've been calling modlets, which can add, remove and change smaller pieces of the game. They can be used together, or they could be added to an overhaul mod, in order to style your game play easier.

These modlets would also exists outside of the Data/Config folder, so if you have made direct XML changes in your Alpha 17.1 Data/Config files, and Steam updated the game to 17.2, you would have lost your changes, or would have to re-merge them in. We've all been there before. But if they existed as modlets, under the Mods folder, they would be safe. And as long as your xpath is still valid to the new XML, it should load up with no additional work on your part.

If we could use xyth's JunkItems modlet, which adds random, scrappable junk items to loot containers, and add them to Valmod Overhaul. Likewise, if Valmod Overhaul did not have the No Ammo modlet (which gives you the ability to unload a gun and get its bullets back without disassembling it), you could drop the NoAmmo modlet into your Mods folder. Headshots only? Want to increase stack sizes? Same deal.

With a properly constructed modlet, we'll be able to piece together new play styles for people to enjoy and share. A modder working on a large overhaul won't have to duplicate work. If they wanted to include the No Ammo mod, they wouldn't have to code it themselves, letting them focus on the bits that make their mod really unique.

Let's get started on your journey...

 
Last edited by a moderator:
what am I doing wrong here

<remove xpath="/block[@name=treeJuniper4m]">

<drop event="Harvest" name="resourceWood" count="30" tag="oreWoodHarvest"/>

</remove>

<append xpath="/block[@name=treeJuniper4m]">

<drop event="Harvest" name="woodenStick" count="10,30" tag="oreWoodHarvest"/>

</append>

 
try...

<remove xpath="/blocks/block[@name=treeJuniper4m]">

<drop event="Harvest" name="resourceWood" count="30" tag="oreWoodHarvest"/>

</remove>

<append xpath="/blocks/block[@name=treeJuniper4m]">

<drop event="Harvest" name="woodenStick" count="10,30" tag="oreWoodHarvest"/>

</append>

 
Try this:

Code:
<remove xpath="/blocks/block[@name='treeJuniper4m']/drop[@event='Harvest' and @name='resourceWood']" />
Remove is a single line.

 
Can anyone help with this ? I am just trying to extend the range of charsimatic nature - a different range for each level of the perk. So far i have this which is a bit of a guess based on something similar by Stallionsden.

<config>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=1]/effect[@name=range]/@value">15</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=2]/effect[@name=range]/@value">30</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=3]/effect[@name=range]/@value">45</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=4]/effect[@name=range]/@value">60</set>

</config>

This isn't working. Some of this is guess work on my part. By the way how do i paste into a window with sliders in this forum ?

Is there anything i can read that explains the xpath naming structure ? For example in this one I have assumed 'range' is refered to as a name but I really don't know if it is referred to as a name. How do you guys know what to call everything in the syntax ? Is there something in notepad ++ that tells you this ? i saw in a video someones notepad ++ was highlighting certain fields but my npad++ doesnt seem to do that. Or is there another program perhaps ? I've tried to check this code on some of the websites that say they say can check it but so far i haven't been able to make any of these checking sites work.

 
Can anyone help with this ? I am just trying to extend the range of charsimatic nature - a different range for each level of the perk. So far i have this which is a bit of a guess based on something similar by Stallionsden.
<config>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=1]/effect[@name=range]/@value">15</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=2]/effect[@name=range]/@value">30</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=3]/effect[@name=range]/@value">45</set>

<set xpath="/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@level=4]/effect[@name=range]/@value">60</set>

</config>

This isn't working. Some of this is guess work on my part. By the way how do i paste into a window with sliders in this forum ?

Is there anything i can read that explains the xpath naming structure ? For example in this one I have assumed 'range' is refered to as a name but I really don't know if it is referred to as a name. How do you guys know what to call everything in the syntax ? Is there something in notepad ++ that tells you this ? i saw in a video someones notepad ++ was highlighting certain fields but my npad++ doesnt seem to do that. Or is there another program perhaps ? I've tried to check this code on some of the websites that say they say can check it but so far i haven't been able to make any of these checking sites work.
Which XML node are you trying to reference? The only node in there that has a level attribute is the effect_description:

Code:
		<effect_description level="1" desc_key="perkCharismaticNatureRank1Desc"/>
		<effect_description level="2" desc_key="perkCharismaticNatureRank2Desc"/>
		<effect_description level="3" desc_key="perkCharismaticNatureRank3Desc"/>
		<effect_description level="4" desc_key="perkCharismaticNatureRank4Desc"/>
		<effect_description level="5" desc_key="perkCharismaticNatureRank5Desc"/>
That xpath would be: /progression/perks/perk[@name=perkCharismaticNature]/effect_group/effect_description[@level=1]

But they don't have a range.

If you are targetting this:

Code:
		<triggered_effect trigger="onSelfProgressionUpdate" action="ModifyCVar" cvar="CharismaticNature" operation="set" value="4" target="selfAOE" target_tags="ally,party" range="15">
			<requirement name="ProgressionLevel" progression_name="perkCharismaticNature" target="self" operation="GTE" value="4"/>
			<requirement name="CVarCompare" cvar="CharismaticNature" target="other" operation="LT" value="4"/>
		</triggered_effect>
Then your xpath would look like this:

/progression/perks/perk[@name=perkCharismaticNature]/effect_group/triggered_effect[@trigger=onSelfProgressionUpdate]/@range

So the @trigger, @range, etc are all referencing the attributes on the xml.

triggered_effect: node. It's referenced by /triggered_effect/

trigger: Attribute. It's referenced by @.

They go together like this, which says "find the node called triggered_effect that has a trigger called onSelfProgressionUpdate"

/triggered_effect[@trigger=onSelfProgressionUpdate]/

Code:
		<triggered_effect trigger="onSelfProgressionUpdate" action="ModifyCVar" cvar="CharismaticNature" operation="set" value="4" target="selfAOE" target_tags="ally,party" range="15">
			<requirement name="ProgressionLevel" progression_name="perkCharismaticNature" target="self" operation="GTE" value="4"/>
			<requirement name="CVarCompare" cvar="CharismaticNature" target="other" operation="LT" value="4"/>
		</triggered_effect>
 
Hmm I'm wanting to change the range values - for each level of the perk they are set at 15, but i would like to change that value to 30, 45, 60 respectively by using xpath. Perhaps including what i thought was the level reference has just confused things.

Given i've seen lots of values changed in lots of modlets i assumed i could do that in this case as well. I dont want to change anything except the range value from 15 to another number, so that range=15 becomes range=30 for example. So yes there are 4 paragraphs that looks like this one all with range=15 in them and i want to have an xpath that points there so that i can edit it. In game that would mean allys can be furher apart than the default distance but still earn xp from each other. I hope that makes some sense, I'm not familiar with this stuff at all.

<effect_group>

<triggered_effect trigger="onSelfProgressionUpdate" action="ModifyCVar" cvar="CharismaticNature" operation="set" value="1" target="selfAOE" target_tags="ally,party" range="15">

<requirement name="ProgressionLevel" progression_name="perkCharismaticNature" target="self" operation="Equals" value="1"/>

<requirement name="CVarCompare" cvar="CharismaticNature" target="other" operation="LT" value="1"/>

</triggered_effect>

I'm still a bit lost though. It seems there needs ot be a way to refer to the progression level as well and that comes after the range entry i want to chnage.

 
Last edited by a moderator:
Hmm I'm wanting to change the range values - for each level of the perk they are set at 15, but i would like to change that value to 30, 45, 60 respectively by using xpath. Perhaps including what i thought was the level reference has just confused things.
Given i've seen lots of values changed in lots of modlets i assumed i could do that in this case as well. I dont want to change anything except the range value from 15 to another number, so that range=15 becomes range=30 for example. So yes there are 4 paragraphs that looks like this one all with range=15 in them and i want to have an xpath that points there so that i can edit it. In game that would mean allys can be furher apart than the default distance but still earn xp from each other. I hope that makes some sense, I'm not familiar with this stuff at all.

<effect_group>

<triggered_effect trigger="onSelfProgressionUpdate" action="ModifyCVar" cvar="CharismaticNature" operation="set" value="1" target="selfAOE" target_tags="ally,party" range="15">

<requirement name="ProgressionLevel" progression_name="perkCharismaticNature" target="self" operation="Equals" value="1"/>

<requirement name="CVarCompare" cvar="CharismaticNature" target="other" operation="LT" value="1"/>

</triggered_effect>

I'm still a bit lost though. It seems there needs ot be a way to refer to the progression level as well and that comes after the range entry i want to chnage.
This will update the 5 ranges that are available, and set them to 30.

Code:
<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate']/@range">30</set>
If you want to change individually, you'll want to look at setting and extra condition on @value.

Code:
<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate' and @value='1']/@range">30</set>

<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate' and @value='2']/@range">30</set>

<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate' and @value='3']/@range">30</set>

<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate' and @value='4']/@range">30</set>
That covers the first 4. The other last one, does not have a @level. Instead, we'll look for something on that line that's not in the other 4 lines. In this case, it has a @buff attribute:

Code:
<set xpath="/progression/perks/perk[@name='perkCharismaticNature']/effect_group/triggered_effect[@trigger='onSelfProgressionUpdate' and @buff='buffPerkCharismaticNature']/@range">30</set>
 
Thanks alot. Loads up fine. You should publish that as a modlet ! I am curious to know where the Party controls are. Any idea ?

 
Thanks alot. Loads up fine. You should publish that as a modlet ! I am curious to know where the Party controls are. Any idea ?
To be completely candid, I have no idea what effect those changes have on the game =D

I'm not sure about the Party controls.

 
  • Like
Reactions: Tin
Can anyone tell me how to make items I've appended use custom icons?

I've got this, for example:

<item name="foodBaconAndEggSandwich">

<property name="HoldType" value="31"/>

<property name="CustomIcon" value="foodBaconAndEggSandwich"/>

<property name="DisplayType" value="food"/>

<property name="Meshfile" value="Items/Misc/parcelPrefab"/>

<property name="DropMeshfile" value="Items/Misc/sack_droppedPrefab"/>

<property name="Material" value="Morganic"/>

<property name="Stacknumber" value="50"/> <!-- STK food -->

<property name="EconomicValue" value="72"/>

<property class="Action0">

<property name="Class" value="Eat"/>

<property name="Delay" value="2.1"/>

<property name="Use_time" value="..."/>

<property name="Sound_start" value="player_eating"/>

</property>

<property name="Smell" value="largeSmell"/>

<property name="Group" value="Food/Cooking"/>

<effect_group tiered="false">

<triggered_effect trigger="onSelfPrimaryActionEnd" action="ModifyCVar" cvar="$foodAmountAdd" operation="add" value="50"/>

<triggered_effect trigger="onSelfPrimaryActionEnd" action="ModifyCVar" cvar="foodHealthAmount" operation="add" value="18"/>

<triggered_effect trigger="onSelfPrimaryActionEnd" action="AddBuff" target="self" buff="buffProcessConsumables"/>

</effect_group>

</item>

And my folder setup is:

7 Days To Die > Mods > MyMod > Config, ItemIcons, and ModInfo > Items

 
Thanks alot. Loads up fine. You should publish that as a modlet ! I am curious to know where the Party controls are. Any idea ?
serverconfig.xml in the root 7 Days To Die folder

<property name="PartySharedKillRange" value="100"/> <!-- The distance you must be within to receive party shared kill xp and quest party kill objective credit. -->

Edit "value=100" is 100 blocks in game

 
Last edited by a moderator:
Can anyone tell me how to make items I've appended use custom icons?
I've got this, for example:

<item name="foodBaconAndEggSandwich">

<property name="HoldType" value="31"/>

<property name="CustomIcon" value="foodBaconAndEggSandwich"/>

<property name="DisplayType" value="food"/>

<property name="Meshfile" value="Items/Misc/parcelPrefab"/>

<property name="DropMeshfile" value="Items/Misc/sack_droppedPrefab"/>

<property name="Material" value="Morganic"/>

<property name="Stacknumber" value="50"/> <!-- STK food -->

<property name="EconomicValue" value="72"/>

<property class="Action0">

<property name="Class" value="Eat"/>

<property name="Delay" value="2.1"/>

<property name="Use_time" value="..."/>

<property name="Sound_start" value="player_eating"/>

</property>

<property name="Smell" value="largeSmell"/>

<property name="Group" value="Food/Cooking"/>

<effect_group tiered="false">

<triggered_effect trigger="onSelfPrimaryActionEnd" action="ModifyCVar" cvar="$foodAmountAdd" operation="add" value="50"/>

<triggered_effect trigger="onSelfPrimaryActionEnd" action="ModifyCVar" cvar="foodHealthAmount" operation="add" value="18"/>

<triggered_effect trigger="onSelfPrimaryActionEnd" action="AddBuff" target="self" buff="buffProcessConsumables"/>

</effect_group>

</item>

And my folder setup is:

7 Days To Die > Mods > MyMod > Config, ItemIcons, and ModInfo > Items

Looks right if your icon is in fact in ItemIcons and if it is named correctly (case sensitive). I personally rarely use the customIcon property (No reason not to use it, I just don't), I just make sure the item name and the icon name match, then drop it in the ItemIcons folder.

One other thing you might try is using a shorter name for the icon, IIRC a few Alphas back an icon name would not show for me with a longer name. I am not aware of problems with long names but it's worth a try.

 
Looks right if your icon is in fact in ItemIcons and if it is named correctly (case sensitive). I personally rarely use the customIcon property (No reason not to use it, I just don't), I just make sure the item name and the icon name match, then drop it in the ItemIcons folder.
One other thing you might try is using a shorter name for the icon, IIRC a few Alphas back an icon name would not show for me with a longer name. I am not aware of problems with long names but it's worth a try.
I forgot I'd posted this. I think I may have had a slight error at the beginning of the <append xpath> line, an extra / possibly. It's sorted now.

- - - Updated - - -

I have been trying to add a property to an existing item but nothing works. Does anyone know how to do this?
What is the property?

 
What is the property?
the code you used in a16 was: <property name="MeltTimePerUnit" value="#"/>

and now I want to add it with the xpath but I don't understand how to do it, I have tried a bunch of ways but nothing work.

I know the property works since I tested it with changing the items.xml manually.

 
* = whatever item name you want to add the property to

# = default melt time on all items in the forge is 0.25, it all extends from unit_iron

Code:
<configs>
<append xpath="/items/item[@name='*']">
<property name="MeltTimePerUnit" value="#"/>
</append>
</configs>
 
Hey guys, wanted to expand on a bit I just figured out, apologies if this has already been covered.

Was trying to increase the yield of resourceCrushedSand from terrDesertGround blocks, but didn't want to bump up the return of resourceClayLump.

Issue was that both resources share much of their path & I was struggling with the syntax needed to isolate one from the other;

<drop event="Harvest" name="resourceCrushedSand" count="11" tag="oreWoodHarvest"/>

<drop event="Harvest" name="resourceClayLump" count="2" tag="oreWoodHarvest"/>

Original from blocks.xml

Code:
<block name="terrDesertGround">
<property name="Material" value="MDesertGround"/>
<property name="Shape" value="Terrain"/>
<property name="Mesh" value="terrain"/>
<property name="Texture" value="185,184,184,184,184,184"/>
<property name="ImposterExclude" value="true"/>
<property name="Map.Color" value="255,221,153"/>
<drop event="Harvest" name="resourceCrushedSand" count="11" tag="oreWoodHarvest"/>
<drop event="Harvest" name="resourceClayLump" count="2" tag="oreWoodHarvest"/>
<drop event="Destroy" count="0"/>
<property class="RepairItems">
	<property name="resourceCrushedSand" value="8"/>
	<property name="resourceClayLump" value="1"/>
</property>
<drop event="Fall" name="resourceCrushedSand" count="11" prob="0.5" stick_chance="0"/>
<property name="Group" value="Decor/Miscellaneous"/>
<property name="CanMobsSpawnOn" value="true"/>
<property name="EconomicValue" value="5"/>
<property name="EconomicBundleSize" value="1"/>
<property name="SellableToTrader" value="false"/>
<property name="FilterTags" value="fterrain"/>
<property name="SortOrder1" value="d0k0"/>
<property name="SortOrder2" value="0050"/>
<property name="DisplayType" value="blockTerrainFertile" />
</block>
Found the clue I needed in your first posts spereii; use of "and". This line now ups sand but leaves clay at default;

Code:
<set xpath="/blocks/block[@name='terrDesertGround']/drop[@event='Harvest' and @name='resourceCrushedSand']/@count">20</set>
Don't know what you'd call/describe this as? "Isolating a specific value when multiple attributes are shared"?

Good luck searching for that right? 0_o :)

Anyway, thought this might be helpful so figured I'd post it.

Thanks a bunch for this thread sphereii, -very- useful!

 
Back
Top