Here's George's post introducing these functions.
Here are the XML functions:George Moromisato wrote:The basic recipe looks like this:
1. In the root element of your extension (<TranscendenceExtension>), add usesXML="true". This tells the engine that you need the XML for all the types to be kept around for you.
2. In <OnGlobalTypesInit>, you may use a new function, typGetXML to get the XML for a type that you wish to override.
3. There are new functions that manipulate the XML returned by typGetXML. For example, you can set attributes or add elements.
4. Once you've manipulated the XML, you may call typCreate to dynamically create a new type or override an existing type.
Code: Select all
(xmlAppendSubElement xml xmlToAdd [index]) -> True/Nil
(xmlAppendText xml text [index]) -> True/Nil
(xmlCreate xml) -> xml
(xmlDeleteSubElement xml index) -> True/Nil
(xmlGetAttrib xml attrib) -> value
(xmlGetAttribList xml) -> list of attribs
(xmlGetSubElement xml tag|index) -> xml
(xmlGetSubElementCount xml) -> number of sub-elements
(xmlGetSubElementList xml [tag]) -> list of xml
(xmlGetText xml [index]) -> text
(xmlGetTag xml) -> tag
(xmlSetAttrib xml attrib value) -> value
(xmlSetText xml text [index]) -> True/Nil
Now I'll demonstrate with a slightly more complicated example than George's. I'll use a request from relanat:
relanat wrote: ↑Fri Mar 10, 2017 1:01 amIs there a way to add <Trade> info to a station without overwriting the whole station code?
...
I would like to addwithout having to add the nearly 2000 lines of Korolov code to a mod to overwrite it.Code: Select all
<SellShip criteria="s L:1-13;" priceAdj="110"/>
So, following George's steps:
Step 1:
Also, if it only affects types in a specific library, you should probably extend that library, so it can't be included in games where it won't do anything. You may also want to include the library so you can use UNIDs from it without declaring <!ENTITY>s for them. In this case, Korolov is definitely part of the Human Space Library, so I'll use that:
Code: Select all
<TranscendenceExtension UNID="&unidKorolovXMLDemo;"
name= "Korolov XML demo"
extends= "&unidHumanSpaceLibrary;"
usesXML= "true"
apiVersion= "35"
version= "1.0"
credits= "Nathaniel Stalberg (NMS)"
>
<Library UNID="&unidHumanSpaceLibrary;"/>
This event is the only time you can change the XML of a type that's already in the game. So the changes will only take effect when starting a new game. However, you can get the XML of types and create new types at other times. (But you can't get the XML of a type that has an override type affecting it after this event. Also, there used to be a bug preventing you from getting the XML of a type that had been created or modified with typCreate, but this was fixed in the 1.7 betas.) In this case I'm going to add a generic <Type> to contain the event, but you can also put it inside another type:
Code: Select all
<Type UNID="&evAddKorolovShipSales;">
<Events>
<OnGlobalTypesInit>
(block (KorolovXML ...)
(setq KorolovXML (typGetXML &stKorolovShipping;))
Since I want to add an element that doesn't already exist, I have to specify it somehow. There are a few options:
- Option A: Just include the XML elements you want to add in one of your own types.
This is the easiest option when you know exactly what you want to add. For instance, I can put relanat's <SellShip> element in my <Type>, after <Events>. This is usually fine, but if what you're adding might actually do something in the type you're adding it to, enclose it in another element that won't do anything, like <XMLToAdd>.
Code: Select all
(setq subelementToAdd (xmlGetSubelement (typGetXML &evAddKorolovShipSales;) 'SellShip))
This is the trickiest to format because the string is going to be parsed in several different steps. The < and > symbols in the string you want to become XML must be replaced by < and > or your mod will not be valid XML. Also, " symbols must be escaped by putting a backslash before them, like this: \", otherwise the TransLisp compiler will think the string ends and you'll get an error, which could be about mismatched quotes, mismatched parenthesis, unknown entity, etc.
Code: Select all
(setq subelementToAdd (xmlCreate "<SellShip criteria=\"s L:1-13;\" priceAdj=\"110\"/>"))
You still have to add any new tags like in option A or B, but you can change their attributes and text, and add subelements as I'll do below. Recommended if you want the XML to vary depending on other code.
Code: Select all
(setq subelementToAdd (xmlCreate "<SellShip/>"))
(xmlSetAttrib subelementToAdd 'criteria "s L:1-13;")
(xmlSetAttrib subelementToAdd 'priceAdj '110)
This has the advantage that you can include <, >, and ", but the disadvantage that you can't use replacements beginning with &, including text UNIDs like &unid;. I don't recommend it unless you know what you're doing. See this thread.
Now it's time to add the new element to the station type's <Trade> element:
Code: Select all
(setq tradeSubelement (xmlGetSubelement KorolovXML 'Trade))
(xmlAppendSubelement tradeSubelement subelementToAdd)
Step 4: Override the type with (typCreate).
Easy enough:
Code: Select all
(typCreate &stKorolovShipping; KorolovXML)
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TranscendenceExtension [
<!ENTITY unidHumanSpaceLibrary "0x00100000">
<!ENTITY unidKorolovXMLDemo "0xE127B100">
<!ENTITY evAddKorolovShipSales "0xE127B101">
]>
<TranscendenceExtension UNID="&unidKorolovXMLDemo;"
name= "Korolov XML demo"
extends= "&unidHumanSpaceLibrary;"
usesXML= "true"
apiVersion= "35"
version= "1.0"
credits= "Nathaniel Stalberg (NMS)"
>
<Library UNID="&unidHumanSpaceLibrary;"/>
<Type UNID="&evAddKorolovShipSales;">
<Events>
<OnGlobalTypesInit>
(block (KorolovXML tradeSubelement subelementToAdd)
(setq KorolovXML (typGetXML &stKorolovShipping;))
(setq subelementToAdd (xmlGetSubelement (typGetXML &evAddKorolovShipSales;) 'SellShip))
(setq tradeSubelement (xmlGetSubelement KorolovXML 'Trade))
(xmlAppendSubelement tradeSubelement subelementToAdd)
(typCreate &stKorolovShipping; KorolovXML)
)
</OnGlobalTypesInit>
</Events>
<SellShip criteria="s L:1-13;" priceAdj="110"/>
</Type>
</TranscendenceExtension>
Code: Select all
(block ((KorolovXML (typGetXML &stKorolovShipping;))) ; step 2
(xmlAppendSubelement (xmlGetSubelement KorolovXML 'Trade) (xmlGetSubelement (typGetXML &evAddKorolovShipSales;) 'SellShip)) ; step 3
(typCreate &stKorolovShipping; KorolovXML) ; step 4
)
Coming soon: Deleting subelements and safely handling types that may not exist, may not have gettable XML, and may not have the expected subelements.