XPATH surgery - Need help with xpath? post here.

Started by skullywag, June 02, 2017, 04:26:23 AM

Previous topic - Next topic

dburgdorf

Quote from: Sixdd on June 09, 2017, 12:01:17 PMThat is actually possible.

Thanks, but what you're describing is using patches to modify existing defs, which I already do in several of my mods. I'm asking if there's any way to use a patch to create a *new* def. I know I can use patches to *modify* ThingDef[defname="Whatever"], but can I use a patch to *create* that def in the first place? That's what I'd like to do, but I don't believe it's actually possible.
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

skullywag

You can only check for a mods existence really in c#. The xpath is running over the defs 1 by 1, so adding 1 in there is not really going to work....i dont think....theres probably some crazy thing you can do but i wouldnt suggest trying it. I think this sits in the realms of c# (and people have done stuff similar already) for now, who knows what that crazy Zorba has planned for the future. :)
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

dburgdorf

Quote from: skullywag on June 09, 2017, 12:43:01 PMThe xpath is running over the defs 1 by 1, so adding 1 in there is not really going to work....

Yeah, that's what I figured. And unfortunately, since the seed defs in "Seeds Please!" use a custom def type -- they're SeedsPlease.SeedDefs, not ThingDefs -- I can't just create the new defs in my code, either, as even though I could easily see if "Seeds Please!" is installed, my mod wouldn't, on its own, know what the hell a "SeedDef" was supposed to be. :)

So much for my attempt to be clever. I guess I'll just release a "Seeds Please!" patch mod for "Wild Cultivation," just like everybody else does for their own mods that add new plants. :D
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

Sixdd

This is what I was talking about when I referenced Cupros code:


<li Class="CuprosAlloys.PatchOperationFindMod">
<modName>Powerless!</modName>


it's from the Cupro's Alloys mod in one of the patches.

And this is the rest of that code which adds an entirely new ThingDef:


<li Class="PatchOperationInsert">
<!-- Inserting code before an attribute places it as a separate def -->
<xpath>/ThingDefs/ThingDef[@Name="CampTableBase"]</xpath>
<Order>Prepend</Order>
<value>
<ThingDef ParentName="BuildingBase">
<DefName>POW_Crucible</DefName>
<label>crucible</label>
<ThingClass>Building_WorkTable</ThingClass>
<Description>A structure dating back to chalcolithic times used for melting metal and creating alloys.</Description>
<graphicData>
<texPath>Cupro/Object/Station/Crucible/Crucible</texPath>
<graphicClass>Graphic_Multi</graphicClass>
<shaderType>CutoutComplex</shaderType>
</graphicData>
<fillPercent>0.25</fillPercent>
<stuffCategories>
<li>Stony</li>
</stuffCategories>
<costStuffCount>60</costStuffCount>
<costList>
<POW_Charcoal>25</POW_Charcoal>
</costList>
<altitudeLayer>Building</altitudeLayer>
<UseHitPoints>true</UseHitPoints>
<destroyable>true</destroyable>
<rotatable>true</rotatable>
<statBases>
<MaxHitPoints>2000</MaxHitPoints>
<WorkToBuild>1500</WorkToBuild>
<Flammability>0</Flammability>
<Cleanliness>-4</Cleanliness>
<Mass>20</Mass>
</statBases>
<Size>(1,1)</Size>
<DesignationCategory>Production</DesignationCategory>
<Passability>PassThroughOnly</Passability>
<canOverlapZones>false</canOverlapZones>
<pathCost>60</pathCost>
<hasInteractionCell>True</hasInteractionCell>
<interactionCellOffset>(0,0,1)</interactionCellOffset>
<surfaceType>Item</surfaceType>
<tickerType>Normal</tickerType>
<comps>
<li>
<compClass>CompQuality</compClass>
</li>
<li Class="CompProperties_AffectedByFacilities">
<linkableFacilities>
<li>POW_Bellows</li>
</linkableFacilities>
</li>
<li Class="CompProperties_Refuelable">
<fuelConsumptionRate>64.0</fuelConsumptionRate>
<fuelCapacity>40.0</fuelCapacity>
<fuelFilter>
<thingDefs>
<li>POW_Charcoal</li>
</thingDefs>
</fuelFilter>
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
</li>
<li Class="Powerless.CompProperties_Smoker">
<smokeStyle>Single</smokeStyle>
<frequencyMin>800</frequencyMin>
<frequencyMax>1200</frequencyMax>
<produceSmokeOnlyWhenUsed>true</produceSmokeOnlyWhenUsed>
<size>0.5</size>
</li>
</comps>
<inspectorTabs>
<li>ITab_Bills</li>
</inspectorTabs>
<building>
<spawnedConceptLearnOpportunity>BillsTab</spawnedConceptLearnOpportunity>
<heatPerTickWhileWorking>1.0</heatPerTickWhileWorking>
</building>
<placeWorkers>
<li>PlaceWorker_ShowFacilitiesConnections</li>
</placeWorkers>
<researchPrerequisites>
<li>POW_Forge</li>
</researchPrerequisites>
</ThingDef>
</value>
</li>


Maybe this still isn't what you were aiming for but I thought it would be relevant.

dburgdorf

Quote from: Sixdd on June 09, 2017, 01:29:53 PMMaybe this still isn't what you were aiming for but I thought it would be relevant.

Well, I'll be damned. I can't try it until I get home tonight, but that just might be exactly what I need.

I apologize for assuming earlier that you weren't addressing my actual request. ;)
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

delheit

#20
Quote from: Sixdd on June 09, 2017, 05:02:46 AM
Yeah don't use the // instead try this

<xpath>*/ThingDef[defName = "Wall"]/costStuffCount</xpath>

The * at the beginning tells it to check all root tags where as the // tells it to check EVERY tag, even non root tags.

EDIT: To elaborate more, anywhere you place a * it will match "anything"

Thank You, */ThingDef is also working, so I guess it should save on performance compared to //ThingDef I can't help but wonder what the correct path is though. :)

Quote from: skullywag on June 09, 2017, 05:52:48 AM
Yep as sixdd has rightly stated, we as people that know the structure of the xml should never have a need for //

however in terms of your second patch costStuffCount doesnt exist on mineableSteel does it? thats what you are adding.

Yea <costStuffCount>5</costStuffCount> is in the Buildings_Structure file under Wall and it later has the stuff categories Woody, Metallic and Stony. All I did was change the 5 to a 10. And it is working in game now with // or */ as above. I was even able to build the walls. (I hope I don't sound like I am arguing, I know your way more experienced then me.)


Update: Oh wait I think I see where the confusion was there. The first example is in fact mineable steel and I change the yield but in the second example I am only changing the cost of building a regular wood wall.
Quote[defName = "Wall"]
Thanks but no that's not what the issue is, The cost to build em is working. :) I just don't know the exactly correct xpath to standard walls.

I guess I will use */ for now until I can find the exact path.

AngleWyrm

#21
Quote from: dburgdorf on June 09, 2017, 12:52:24 PM
...unfortunately, since the seed defs in "Seeds Please!" use a custom def type -- they're SeedsPlease.SeedDefs, not ThingDefs -- I can't just create the new defs in my code, either, as even though I could easily see if "Seeds Please!" is installed, my mod wouldn't, on its own, know what the hell a "SeedDef" was supposed to be.

Instead of an xpath that looks like this: */ThingDef[defName = "DiningChair"]/costList
The search can be changed to look for something like this: */SeedsPlease.SeedDefs
Which should return a set of all SeedDefs, or nothing if it can't find SeedsPlease records.

The sequence patch operation then looks something like so:
[patch sequence]
   [test for existence of a SeedsPlease record, or bail if none are found]
   [do a series of seed-related patches]
[/end of patch sequence]

Attached is a mini-mod called testing which is just an easy drop-in for mucking about with xmls and patching.

<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid XML Studio 2009 - the LAST FREE Community Edition 7.0.2.746

    Patch and xpath testing

        Tests
        1). File name that has spaces for legibility
        2). Replacement of known-to-exist core element
        3). Creation of a new Def record to the Defs collection
        4). Conditionally add a cost list to dining chair if it doesn't already have one
    -->
<Patch>
    <!--
        Testing replacement of a known-to-exist element
        Replace default "Allow Rotten" behavior
    -->
    <Operation Class="PatchOperationReplace">
        <xpath>*/SpecialThingFilterDef[defName = "AllowRotten"]/allowedByDefault</xpath>
        <value>
            <allowedByDefault>false</allowedByDefault>
        </value>
    </Operation>
    <!--
        Testing the addition of a new def record to the Defs collection
        Add a new Def with the defName of 'someThingy'
    -->
    <Operation Class="PatchOperationAdd">
        <xpath>/Defs</xpath>
        <value>
            <!-- new def record to add to Defs collection -->
            <Def>
                <defName>someThingy</defName>
                <!-- other elements of the def -->
            </Def>
        </value>
    </Operation>
    <!--
        Conditional testing
        Check if Dining Chair already has a cost list, add one if it doesn't
        then work with the cost list
    -->
    <Operation Class="PatchOperationSequence">
        <success>Always</success>
        <operations>
            <li Class="PatchOperationTest">
                <xpath>//ThingDef[defName = "DiningChair"]/costList</xpath>
                <success>Invert</success>
            </li>
            <li Class="PatchOperationAdd">
                <xpath>//ThingDef[defName = "DiningChair"]</xpath>
                <value>
                    <costList />
                </value>
            </li>
        </operations>
    </Operation>
    <!-- at this point the dining chair has a cost list -->
    <Operation Class="PatchOperationAdd">
        <xpath>//ThingDef[defName = "DiningChair"]/costList</xpath>
        <value>
            <Cloth>5</Cloth>
        </value>
    </Operation>
</Patch>


[attachment deleted by admin due to age]
My 5-point rating system: Yay, Kay, Meh, Erm, Bleh

dburgdorf

Quote from: AngleWyrm on June 09, 2017, 02:28:41 PM....

First, as I've already noted, I am familiar with the use of XML patches to *modify* defs. I had inquired about the possibility of using them to *create* defs. Second, the portion of my comment that you quoted wasn't even discussing XML at all, but was specifically referring to whether something could be done in my mod's *code* (that is, C#).

Fortunately, I already got the information I needed from folk who actually understood what I was asking about.
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

AngleWyrm

#23
Have you considered investing in some reading glasses?

Quote from: AngleWyrm on June 09, 2017, 02:28:41 PM

        3). Creation of a new Def record to the Defs collection

    <!--
        Testing the addition of a new def record to the Defs collection
        Add a new Def with the defName of 'someThingy'
    -->
    <Operation Class="PatchOperationAdd">
        <xpath>/Defs</xpath>
        <value>
            <!-- new def record to add to Defs collection -->
            <Def>
                <defName>someThingy</defName>
                <!-- other elements of the def -->
            </Def>
        </value>
    </Operation>

My 5-point rating system: Yay, Kay, Meh, Erm, Bleh

delheit

Quote from: AngleWyrm on June 09, 2017, 02:28:41 PM

Attached is a mini-mod called testing which is just an easy drop-in for mucking about with xmls and patching.


Cool code, helped me learn more about something else I was attempting.

AngleWyrm


Wondering about optimization


The subject records are the set of backstories contained in the Defs collection that have WorkDisables tag(s)
/Defs/REB_Code.BackstoryDef/WorkDisables

The goal is to perform two patch operations based on content
  • Insert (or Add) a ForcedTrait/li element according to an arbitrary mapping of some workDisable -> some forcedTrait.
  • Remove the WorkDisables element after processing the additions/insertions
My question is this: Is there a mechanism that will help to avoid making the full search for each of the workdisables? Can I perform a main search once that returns sub-groups?


My 5-point rating system: Yay, Kay, Meh, Erm, Bleh

craus

Hi guys, Hope you are fine.
This is an example of what i want to do but idk why it does not work.
<Patch>
   <Operation Class="PatchOperationAdd">
     <xpath>/ThingDefs/ThingDef[defName = "SleepingSpot"]</xpath>
     <value>
    <researchPrerequisites><li>HospitalBed</li></researchPrerequisites>
     </value>
   </Operation>
</Patch>

I want to add research prerequisites to some things but i cant make it work.

Sixdd

Not sure why that isn't working but you could always try this:

<Patch>
   <Operation Class="PatchOperationInsert">
     <xpath>/ThingDefs/ThingDef[defName = "SleepingSpot"]/defName</xpath>
     <value>
       <researchPrerequisites><li>HospitalBed</li></researchPrerequisites>
     </value>
   </Operation>
</Patch>


I'm not on my PC or I'd test it but that should work I think.

kaptain_kavern

Maybe because it's the wrong root node ;-)

Try with Buildings\ThingDef\...

craus

Quote from: kaptain_kavern on June 16, 2017, 08:22:22 PM
Maybe because it's the wrong root node ;-)

Try with Buildings\ThingDef\...

OMG it works. Thanks so much! I was gonna start rewriting every def I wanted to change. Now with this I can finally do the changes I want without touching vanilla def and files.