Editing Modding Tutorials/Linking XML and C

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 3: Line 3:
 
[[Modding Tutorials/Writing custom code|Writing custom code]] is all well and good if you can't force RimWorld to use it! Here are three ways of linking your Code to the XML and vice versa.
 
[[Modding Tutorials/Writing custom code|Writing custom code]] is all well and good if you can't force RimWorld to use it! Here are three ways of linking your Code to the XML and vice versa.
  
=Using your C# from XML=
+
=A classy design pattern=
==A classy design pattern==
 
 
RimWorld leans heavily on Object Oriented Programming and will often expose the specific class of a Def to the XML. They're often called a workerClass, thingClass, but obviously can be named anything. Keep a look out for these, they're sometimes subtle.
 
RimWorld leans heavily on Object Oriented Programming and will often expose the specific class of a Def to the XML. They're often called a workerClass, thingClass, but obviously can be named anything. Keep a look out for these, they're sometimes subtle.
  
===Examples===
+
==Examples==
 
<source lang ="xml">
 
<source lang ="xml">
 
<BiomeDef>
 
<BiomeDef>
Line 17: Line 16:
 
<source lang ="xml">
 
<source lang ="xml">
 
<inspectorTabs>
 
<inspectorTabs>
   <li>ITab_Art</li><!-- That's a class! -->
+
   <li>ITab_Art</li>
 
</inspectorTabs>
 
</inspectorTabs>
 
</source>
 
</source>
  
==A "Classy" pattern==
+
=A "Classy" pattern=
 
It is possible to overwrite the default class associated with a Def (or field in a def) by specifying the Class by attribute. The most common usage of this you've undoubtedly seen before is in Components: <source lang = "xml">
 
It is possible to overwrite the default class associated with a Def (or field in a def) by specifying the Class by attribute. The most common usage of this you've undoubtedly seen before is in Components: <source lang = "xml">
 
<comps>
 
<comps>
Line 30: Line 29:
 
This class override is more widely applicable than just [[Modding Tutorials/Custom Comp Classes|comps]]. It's possible to overwrite or specify almost any type you wish. Keep [[Modding Tutorials/Compatibility|Compatibility]] in mind when doing this: in the end each object can only be one [[Modding Tutorials/Def classes|Class]].
 
This class override is more widely applicable than just [[Modding Tutorials/Custom Comp Classes|comps]]. It's possible to overwrite or specify almost any type you wish. Keep [[Modding Tutorials/Compatibility|Compatibility]] in mind when doing this: in the end each object can only be one [[Modding Tutorials/Def classes|Class]].
  
===Example===
+
==Example==
'''Editor's Note''': using extension classes for Defs is no longer recommended. To add fields to defs, use [[Modding Tutorials/DefModExtension|DefModExtensions]] instead.
 
 
 
 
<source lang ="xml">
 
<source lang ="xml">
 
<!-- Generate faction base -->
 
<!-- Generate faction base -->
Line 50: Line 47:
 
</source>
 
</source>
  
==You define yourself==
+
=You define yourself=
 
Another possibility is to supply your own type in the XML. The most well-known example of this is [https://github.com/RimWorld-CCL-Reborn/AlienRaces/wiki/Let%27s-Start Alienraces]. The [https://github.com/RimWorld-CCL-Reborn/AlienRaces/blob/master/Source/AlienRace/AlienRace/ThingDef_AlienRace.cs ThingDef_AlienRace] inherits from regular [[Modding Tutorials/ThingDef|ThingDef]], and adds the alienRace tag to it. The alienRace tag then holds more information, a sample of which is shown below.
 
Another possibility is to supply your own type in the XML. The most well-known example of this is [https://github.com/RimWorld-CCL-Reborn/AlienRaces/wiki/Let%27s-Start Alienraces]. The [https://github.com/RimWorld-CCL-Reborn/AlienRaces/blob/master/Source/AlienRace/AlienRace/ThingDef_AlienRace.cs ThingDef_AlienRace] inherits from regular [[Modding Tutorials/ThingDef|ThingDef]], and adds the alienRace tag to it. The alienRace tag then holds more information, a sample of which is shown below.
  
 
One benefit of this over the annotation method above (the "Classy" pattern) is that the added control and restriction of scope is increased compatibility with over mods. It's theoretically also easier to further subclass the AlienRace def by annotation.
 
One benefit of this over the annotation method above (the "Classy" pattern) is that the added control and restriction of scope is increased compatibility with over mods. It's theoretically also easier to further subclass the AlienRace def by annotation.
  
===Example===
+
While most implementations have limited themselves to Defs, there is no known technical reason to believe this pattern can't be applied to fields directly.
 +
 
 +
==Example==
 
<source lang = "xml">
 
<source lang = "xml">
 
<AlienRace.ThingDef_AlienRace ParentName="BasePawn">
 
<AlienRace.ThingDef_AlienRace ParentName="BasePawn">
Line 74: Line 73:
 
</source>
 
</source>
  
==Serialising custom classes==
+
=Serialising custom classes=
 
It may sometimes be required to read/write your own datatype to XML. While we all love long strings with comma separated values, there are many cases where this is not a good idea. For that, RimWorld offers a ''LoadDataFromXmlCustom'' method. When RimWorld comes across your type during load, and the class defining that type contains the ''LoadDataFromXmlCustom'', RimWorld will use that method to parse the XML. This is done through the magic of reflection.
 
It may sometimes be required to read/write your own datatype to XML. While we all love long strings with comma separated values, there are many cases where this is not a good idea. For that, RimWorld offers a ''LoadDataFromXmlCustom'' method. When RimWorld comes across your type during load, and the class defining that type contains the ''LoadDataFromXmlCustom'', RimWorld will use that method to parse the XML. This is done through the magic of reflection.
  
Line 99: Line 98:
 
</source>
 
</source>
  
==Common issues==
+
=Common issues=
 
You need to specify your exact Namespace.Class. There are no two ways around it. You also need to supply RimWorld with the assembly containing the type and namespace specified.
 
You need to specify your exact Namespace.Class. There are no two ways around it. You also need to supply RimWorld with the assembly containing the type and namespace specified.
 
=Using your XML from C#=
 
There are times you'll need to use a Def or other value defined in XML.
 
 
==DefOf==
 
Any class with the [DefOf] annotation will automatically have its fields filled with their corresponding Def. You can then access it in other code like you'd access any DefOf, like ThingDefOf. The below example would be used as ''SomeDef def = MyDefOf.JustOneExampleDefName;''.
 
 
'''Advantages''':
 
* It's run-time fast.
 
* It's easy.
 
* It moves errors to startup, rather than at runtime. Early warnings save considerable testing and debugging!
 
** If there's an error in your code (like a typo in the defName, or a missing Def), it will detect that as soon as the game starts, rather than when it's trying to use it.
 
 
'''Disadvantages''':
 
* Referencing Defs directly in code means XML changes may not be reflected properly.
 
** For example, if you have behavior linked directly to a specific def, making other defs with the same behavior would require modifying the C# code.
 
* DefOfs don't get their fields filled until after the game is done loading Defs.
 
** This means using a DefOf before it is properly initialised gets you ''null'' - which the DefOf class is supposed to prevent.
 
* Has a negative influence on startup times. <ref>It uses reflection to find and fill the fields. This probably isn't the quickest, but the extent of it hasn't been measured.</ref>
 
 
<source lang = "csharp">
 
[DefOf]
 
public static class MyDefOf
 
{
 
    public static SomeDef JustOneExampleDefName;
 
    public static SomeDef AnotherExampleDefName;
 
    public static SomeDef YetMoreExampleDefName;
 
 
    static MyDefOf()
 
    {
 
        DefOfHelper.EnsureInitializedInCtor(typeof(MyDefOf));
 
    }
 
}
 
</source>
 
The fields have to be static and public.
 
 
===That weird constructor===
 
It's there for your own good. If you're trying to use a Def before RimWorld had a chance to fill the field with a proper reference, it will return null. You don't want that. This constructor warns against that.
 
 
==DefDatabase==
 
If you only need to use a certain Def occasionally, you can look it up in the DefDatabase directly.
 
<source lang = "csharp">SomeDef def = DefDatabase<SomeDef>.GetNamed("JustOneExampleDefName");</source>
 
 
'''Advantages''':
 
* Is allowed to return null (silent failure is an option).
 
* Does not require an entire class.
 
* Is open to string based shenanigans.
 
 
'''Disadvantages''':
 
* Is allowed to return null. If you're not prepared for it to return null, Bad Things Happen.
 
* Slower than a DefOf. (Altho if you put the def in a static variable, this is somewhat negated)
 
* Prone to typos.
 
  
 
=See also=
 
=See also=

Please note that all contributions to RimWorld Wiki are considered to be released under the CC BY-SA 3.0 (see RimWorld Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

Cancel Editing help (opens in new window)

Template used on this page:

This page is a member of 1 hidden category: