A17; changes

Started by Fluffy (l2032), May 06, 2017, 08:40:27 AM

Previous topic - Next topic

Fluffy (l2032)

Let's consolidate our efforts, and report changes in the modding API in this thread.

Patches
You can now use xpath selectors to surgically change properties in vanilla and other mods' defs - so you don't have to replace them!.
Some examples; https://gist.github.com/zorbathut/99a3858fafd2dc9bea8f685ed6b35556
Xpath selectors; https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx

I'd like to invite Zorba and/or any modders that have tested this system to provide more examples and pointers.

Scribing
All the Scribe_XXX.LookXXX() methods are now just Scribe_XXX.Look(), API doesn't appear to have any further changes.

Under the hood, saving and loading of data has been split into two subcomponents of the Scribe; Scribe.loader & Scribe.saver. If you used Scribe to manually load/save data, you'll have to do some minor refactoring. API doesn't appear to have any further changes. Note that the addition of Settings (see below) might mean you don't need to manually call the scribe at all anymore.

Mod Class
There's now a 'Mod' class you can inherit from. It's a simple base class, which gets constructed after all defs are loaded. As such, it's a useful entry point, but it can't completely replace HugsLib's ModBase class (specifically, there's no hook for running code after this mod is loaded, but before other mods further down the list are loaded).

Settings Class
The Mod class also gives access to a Settings object. Settings can basically be anything (but not references to objects in a game!), you'll have to provide your own ExposeData method to save/load the data. You'll also need to provide a Mod.DoSettingsWindowContents() method to render the UI parts. As far as I can see, there's no default settings handlers for simple data types, but they're easy enough to make yourself (hint; Verse.Widgets, or Verse.Listing).

Components
GameComponent, WorldComponent, MapComponent
All of these now have a handy amount of virtual methods corresponding to various events in their lifecycles, making it much easier to attach data to the correct 'scope'. (e.g. attaching data to game/world/mapComponent to make sure it doesn't 'bleed' over when a player starts/loads another game, world, map). Finally, MapComponents are now injected into existing save games when the map is loaded and new mods are added! (or at least I think they are, that's what the code seems to imply).

MainTabs
'Pawn list' main tabs have been completely refactored, and are now def-based, with a def for each table and column. MainTabDefs themselves are now MainButtonDefs.

Commonality
ApparelProperties.commonality appears to have been refactored into ThingDef.generateCommonality. The same may be true for weapons, etc.

Zhentar

#1
A simple patch example, adding a designator to the orders category: https://github.com/Zhentar/ZhentarTweaks/blob/a2007f07340f47e17ed5a63109b7c589dc5ca6a9/Patches/Tweaks_Patches.xml

A simple mod settings example: https://github.com/Zhentar/ZhentarTweaks/blob/3e107f7518f55305406f3bccf96f53a846a1a4d8/Source/LetterStackDetour.cs


edit: And I can verify, MapComponent injection is no longer necessary; they will be automatically added to in progress games.

Shinzy

#2
Quote from: Fluffy (l2032) on May 06, 2017, 08:40:27 AM
Let's consolidate our efforts, and report changes in the modding API in this thread.

Patches
You can now use xpath selectors to surgically change properties in vanilla and other mods' defs - so you don't have to replace them!.
Some examples; https://gist.github.com/zorbathut/99a3858fafd2dc9bea8f685ed6b35556
Xpath selectors; https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx

I'd like to invite Zorba and/or any modders that have tested this system to provide more examples and pointers.

Zorba the hutt has promised to (eventually) write up proper documentationmabobthingie for these
But to get anyone started here's a VERY very simple mod I made (with tonnes of help from Skully and lil tip from Zorbs to understand the thing)
for vanilla pants to have worn graphics without overwriting the vanilla def

Edit: Check out Zhentar's introduction to patching few posts below for more indepth help! ;D


[attachment deleted by admin due to age]

Zhentar

Some other changes of note:

Many enums have been moved to Defs (such as Letter types and Flesh types, for example). This isn't intended to eliminate detouring to modify these behaviors; for the most part behaviors are still hardcoded (Zorba doesn't think he can guess which flags are/aren't worth adding, and I think he's right).

A "ModDefExtension" list was added to the base Def definition. This is to allow mods to add their own custom fields to defs without having to subclass defs (and patch operations can be used to add your fields to core defs as well).

RemingtonRyder

Comments aren't allowed in Patch files (an error about expected Operation results). Bug or intended?

Shinzy

#5
Quote from: MarvinKosh on May 07, 2017, 02:27:57 AM
Comments aren't allowed in Patch files (an error about expected Operation results). Bug or intended?

<!-- these things, yeah? -->
They should work, I tried just now!

Edit: Having used them some more now. It seems like they only work if they're inside the operation tags
Update: Having tried again, cause I'm stubborn like that. They seem to work regardless where you put them now

Zhentar


AngleWyrm


Quote from: Zhentar on May 07, 2017, 11:08:16 PM
I've written up a draft Introduction to PatchOperation
Thanks, great stuff!

I've got to go play around with this puppy
My 5-point rating system: Yay, Kay, Meh, Erm, Bleh

dburgdorf

Quote from: Zhentar on May 07, 2017, 11:08:16 PMI've written up a draft Introduction to PatchOperation

I'm guessing that you'll still have a conflict if mod A, which replaces a def, is loaded after mod B, which patched the vanilla def. Is that correct?

However, if mod A is loaded first... mod B will end up patching mod A's def?
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

Shinzy

Quote from: dburgdorf on May 08, 2017, 03:35:32 PM
Quote from: Zhentar on May 07, 2017, 11:08:16 PMI've written up a draft Introduction to PatchOperation

I'm guessing that you'll still have a conflict if mod A, which replaces a def, is loaded after mod B, which patched the vanilla def. Is that correct?

However, if mod A is loaded first... mod B will end up patching mod A's def?

The really smart people have told me patching happens after all the defs are loaded so in the case you describe there's shouldn't be no worries
but there's a definite possibility for some bad patchin' and crazy combination of things'n'stuff ruining every ones day. But I think that goes with just about anything

Zhentar

To be clear, this means Mod A can patch core Defs and Mod B Defs, and Mod B can patch core Defs and Mod A defs, regardless of what order Mod A and Mod B load in. Patches get applied in mod load order, so if both mods try to patch the same thing, the mod load order still determines who wins.

XeoNovaDan

#11
Pretty neat feature going on here, and I've been playing around with it a little, but I have a question: how do you go about adding something to a list item. Say I wanted to add a new pawn type to a faction's pawnGroupMakers, but I only wanted to modify one listed item as opposed to all of them. Would I set up the xpath like this if I wanted to add to the first item in the list (as an example):


<Operation Class="PatchOperationAdd">
  <xpath>//FactionDef[defName = "Tribe"]/pawnGroupMakers/li[0]</xpath>
  <value>
    <PawnDefNameHere>123</PawnDefNameHere>
  </value>
</Operation>


Bearing in mind this is the section I want to modify:


    <pawnGroupMakers>
      <li>
        <kindDef>Normal</kindDef>
        <options>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
          <TribalChief>70</TribalChief>
        </options>
      </li>
      <li>
        <kindDef>Trader</kindDef>
        <traders>
          <TribalTrader>1</TribalTrader>
        </traders>
        <carriers>
          <Muffalo>1</Muffalo>
          <Dromedary>1</Dromedary>
        </carriers>
        <guards>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
        </guards>
      </li>
      <li>
        <kindDef>FactionBase</kindDef>
        <options>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
          <TribalChief>70</TribalChief>
        </options>
      </li>
    </pawnGroupMakers>


And of course this is the end-outcome I'd want with the patch:


<Operation Class="PatchOperationAdd">
  <xpath>//FactionDef[defName = "Tribe"]/pawnGroupMakers/li[0]</xpath>
  <value>
    <PawnDefNameHere>123</PawnDefNameHere>
  </value>
</Operation>


Bearing in mind this is the section I want to modify:


    <pawnGroupMakers>
      <li>
        <kindDef>Normal</kindDef>
        <options>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
          <TribalChief>70</TribalChief>
          <PawnDefNameHere>123</PawnDefNameHere>
        </options>
      </li>
      <li>
        <kindDef>Trader</kindDef>
        <traders>
          <TribalTrader>1</TribalTrader>
        </traders>
        <carriers>
          <Muffalo>1</Muffalo>
          <Dromedary>1</Dromedary>
        </carriers>
        <guards>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
        </guards>
      </li>
      <li>
        <kindDef>FactionBase</kindDef>
        <options>
          <TribalWarrior>60</TribalWarrior>
          <TribalArcher>100</TribalArcher>
          <TribalChief>70</TribalChief>
        </options>
      </li>
    </pawnGroupMakers>

Shinzy

Quote from: XeoNovaDan on May 20, 2017, 09:15:16 AM
Pretty neat feature going on here, and I've been playing around with it a little, but I have a question: how do you go about adding something to a list item.

I used the insert operation to add thing in a list,
<Operation Class="PatchOperationInsert">

<!-- Add facility link to vanilla bench-->

<order>Append</order>
  <xpath>//ThingDef[defName = "HiTechResearchBench"]/comps/li[contains(@Class,'CompProperties_AffectedByFacilities')]/linkableFacilities/li</xpath>
  <value>
  <li>ApparelloSchematics</li>
  </value>
</Operation>


Yours should work in similar fashion if you switch to the operationInsert
The difference between insert and add as Zorba explained it:
Quote from: Zorba the hutt"add" adds a child. "insert" adds a sibling. I possibly should have chosen better names for those
;D

XeoNovaDan

OK, thanks!

Also, what are all of the parameters (is that the right term?) for each aspect - so there's

WhateverDef[defName = "DefNameHere"]

but I didn't know you could search for what a list item contains with

li[contains(@WhateverYouAreLookingFor)]

Shinzy

Quote from: XeoNovaDan on May 20, 2017, 09:33:53 AM
OK, thanks!

Also, what are all of the parameters (is that the right term?) for each aspect - so there's

WhateverDef[defName = "DefNameHere"]

but I didn't know you could search for what a list item contains with

li[contains(@WhateverYouAreLookingFor)]

These may be of help, I'm still very new with xpath stuff
https://www.w3schools.com/xml/xpath_syntax.asp