Difference between revisions of "Modding Tutorials/Custom Comp Classes"

From RimWorld Wiki
Jump to navigation Jump to search
(→‎Cautions, traps, etc: better example)
Line 72: Line 72:
 
=== Cautions, traps, etc ===
 
=== Cautions, traps, etc ===
 
If you have the same comp in an abstract def and attempt to redefine it in a child def, it will get counted twice.  It's possible to get around this in the code, if you want to have default comps:
 
If you have the same comp in an abstract def and attempt to redefine it in a child def, it will get counted twice.  It's possible to get around this in the code, if you want to have default comps:
 +
 +
  <ThingDef Name=ParentWithDefault ... Abstract=true>
 +
    ...
 +
    <comps>
 +
      <l<nowiki>i</nowiki> Class="MyCompPropertiesWithDefault">
 +
        <myValue>3</myValue><!--default!-->
 +
      </l<nowiki>i</nowiki>>
 +
    </comps>
 +
  </ThingDef>
 +
  <ThingDef ParentName="ParentWihtDefault">
 +
    ...
 +
    <comps>
 +
      <l<nowiki>i</nowiki> Class="MyCompPropertiesWithDefault">
 +
        <myValue>5</myValue><!-- override default!-->
 +
      </<nowiki>l</nowiki>i>
 +
    </comps>
 +
  </ThingDef>
 +
 +
  
 
   public class MyLinkedCompThing : ThingComp
 
   public class MyLinkedCompThing : ThingComp
Line 82: Line 101:
 
       //  This allows a default abstract def with the comp
 
       //  This allows a default abstract def with the comp
 
       //  and child def to change the comp value:
 
       //  and child def to change the comp value:
       CompDeepStorage[] list = this.parent.GetComps<CompDeepStorage>().ToArray();
+
       MyCompProprtiesWithDefault[] list = this.parent.GetComps<MyCompPropertiesWithDefault>().ToArray();
 
       // Remove everything but the last entry; harmless if only one entry:
 
       // Remove everything but the last entry; harmless if only one entry:
 
       for (var i = 0; i < list.Length-1; i++)
 
       for (var i = 0; i < list.Length-1; i++)

Revision as of 16:33, 15 December 2018

Creating a custom comp class is a convenient way to add new functionality to RimWorld.

Prerequisites

def (xml) and C# structure

Setup, Defs, and Classes

You will have some custom def and it will have something like this:

Defs (xml)

 <ThingDef ...>
   ...
   ...
   <comps>
     <li Class="MyNamespace.MyCompProperties">
       <myCustomCompProperty>some value</myCustomCompProperty>
       <mySecondCompProp>4</mySecondCompProp>
     </li>
     <li>
       <!-- this is kind of like <tag>MN.MyCustomTag</tag>:-->
       <compClass>MyNamespace.MyCustomThingComp</compClass>
     </li>
   </comps>
 </ThingDef>

C#

 namespace MyNamespace // For example, LWM.ModName - by using your 
                       //   handle/name/etc, you almost certainly guarantee uniqueness
 {
 //////////// <li</nowiki Class="MyNamespace.MyCompProperties"> ////////////'''
  public class MyCompProperties : CompProperties ''// Name this as you wish, of course''
  {
    public Properties() {
      this.compClass = typeof(MyNamespace.MyLinkedCompThing); ''// rename as appropriate''
    }
    public string myCustomCompProperty; ''// Name matches def, of course''
    public int mySecondCompProp = 1; ''// Can set default values''
  }
  
  ''// this ThingComp is used to actually access the comp property defined above''
  '''''// this is not "<compClass>MyNamespace.MyCustomThingComp</compClass>"'''''
  public class MyLinkedCompThing : ThingComp
  {
    public string myCustomCompProperty
    {
      get
      {
        return ((MyCompProperties)this.props).myCustomCompProperty;
      }
    }
    public int mySecondCompProperty ''// Have to get all the names right''
    { get  { return ((MyCompProperties)this.props).mySecondCompProperty; } } ''//etc''
  }
  '''//////////// <compClass>MyNamespace.MyCustomThingComp</compClass> ////////////'''
  public class MyCustomThingComp : ThingComp
  {
    public override void CompTick()
    {
      // do stuff
    }
    public override void CompTickRare() //etc
    public override ... // Check out Verse/ThingComp.cs for more ideas
  }
  } // end MyNamespace

=== Accessing your Comps ===
Just setting up your custom comps doesn't do you a lot of good if you can't access them!

'''To do'''

=== Cautions, traps, etc ===
If you have the same comp in an abstract def and attempt to redefine it in a child def, it will get counted twice.  It's possible to get around this in the code, if you want to have default comps:

  <ThingDef Name=ParentWithDefault ... Abstract=true>
    ...
    <comps>
      <l<nowiki>i Class="MyCompPropertiesWithDefault">
       <myValue>3</myValue>
     </li>
   </comps>
 </ThingDef>
 <ThingDef ParentName="ParentWihtDefault">
   ...
   <comps>
     <li Class="MyCompPropertiesWithDefault">
       <myValue>5</myValue>
     </li>
   </comps>
 </ThingDef>


 public class MyLinkedCompThing : ThingComp
 {
   public string myCustomCompProperty //etc
   
   public override void Initialize (CompProperties props) {
     base.Initialize(props);
     // Remove duplicate entries and ensure the last entry is the only one left
     //   This allows a default abstract def with the comp
     //   and child def to change the comp value:
     MyCompProprtiesWithDefault[] list = this.parent.GetComps<MyCompPropertiesWithDefault>().ToArray();
     // Remove everything but the last entry; harmless if only one entry:
     for (var i = 0; i < list.Length-1; i++)
     {
       this.parent.AllComps.Remove(list[i]);
     }
   }
 
 ///etc
 }