.NET dll integration question

Started by tychoruniko, February 27, 2014, 07:26:03 PM

Previous topic - Next topic

tychoruniko

So I have plugged the .dll files from RimWorld into VisualStudio and gotten my mostly empty class to compile cleanly. I have been exploring what source code is exposed by metadata from the game AI and GUI dlls, and there is a heck of a lot there but obviously there is no documentation for any of the classes, properties, or methods.

Does this information exist somewhere? If so, could someone point me in the direction of it? If not, could someone give me a clue on delving into building simple custom AIs or GUIs? This has suddenly become a passion project for me; it's helping me stay sane and take breaks from the brain-grinding of staring blankly at my computer screen trying to figure out why some stupid ASP.NET MVC website view is giving me a 404 >_O. But anyway...

Thanks, mates! :D

Rokiyo

Well, it's not exactly documentation, but if you download ILSpy, you can use it to open up Assembly-CSharp.dll and you'll be able to read through all of the game's code.

tychoruniko

Hmm, I will give that a try. If need be, I could write a documentation add on to use with VisualStudio when doing this. Learning a whole project like this with no guidance will take quite some time though.

Rokiyo

Yup, I've only just barely scratched the surface myself.

I've found the XML defs quite helpful in terms of providing clues on where to search the code: generally where the XML refers to something, I've found that it is either listed in an enum somewhere, or is a Class defined in the default namespace.

tychoruniko

Wow, so much to go through. I guess the place to start is to make a goal and figure out every step to accomplish it... hmm...

I'm going to say my first goal is to create a piece of furniture that opens up a little custom GUI when clicked on, sort of like the bill GUI for the oven but that does nothing yet except let you close it. Creating new furniture is easy enough just through the XML. The rest of it I will try to figure out.  :D

Darker

Guys it would be really useful if you'd be taking notes of your discoveries here :)
Please... Throw human readable errors on savefile parsing failure!!!
Rim world editor Editor on GIT

Architect

I'll start then. IntVec3 is a type referring to grid positions on the world. So for instance if you were trying to see if somewhere above was roofed, you could use the base.Position + IntVec3.north as the positional argument.

Another type is IntRot, which refers to rotational stuff. Checking rotations would be something like:
if (this.rotation == IntRot.north) {...}
that would basically check if the rotation was the default rotation.
Check out BetterPower+ and all its derivatives by clicking the picture below.

It adds many new methods of power generation and uses for it, as well as other things such as incidents.


tychoruniko

I've been going through the decompiled code, and I've come up with a few things to share. I'll post it here in the form of a commented version of some files, starting with the Incident_MiracleHeal example mod.

// Include basic system functionality for .NET
using System;
using System.Linq;
// Include required libraries for Rimworld
using UI;
using UnityEngine;

// Create the namespace for your mod classes to reside in
namespace RimWorldTestMod
{
    /// <summary>
    /// The Incident_MiracleHeal class inherits from the generic IncidentDef class.
    /// The IncidentDef class has these inheritable values:
    ///     public float chance;
    ///         Effects the odds of this incident actually occuring when the Storyteller finds this incident in the queue.
    ///     public bool global;
    ///         Not sure what this does; the only two incidents I have found that do not set this to true are TraderArrivalGeneral and TraderArrivalSlaver.
    ///     public IncidentFavorability favorability = IncidentFavorability.Neutral;
    ///         This sets whether this incident is considered good, bad, or neutral for the colony. Probably used by the Storyteller to pick what type of incident to use.
///     public IncidentThreatLevel threatLevel;
    ///         This sets whether this incident is considered a big threat, small threat, or no threat to the colony. Probably used by the Storyteller to pick incidents.
///     public IncidentPopulationEffect populationEffect = IncidentPopulationEffect.None;
    ///         This tells the game whether this incident will increase, reduce or have no effect on the population of the colony. Probably used by the Storyteller.
///     public int minRefireInterval;
    ///         This sets the minimum length of time between this incident being allowed to repeat. Not sure of the units of time though.
///     public bool pointsScaleable;
    ///         Not sure what points are for and what making them scalable would do.
///     public int uniqueSaveKey;
    ///         A unique integer defining this incident, so that the incident will still exist between save/load cycles. Prevents incidents that stay active for a time
    ///         from being cleared cheatily by quiting and reloading.
    /// </summary>
public class Incident_MiracleHeal : IncidentDef
{


        // TryExecute is the main method of any incident. When the incident is excecuted, this is the method called to do so.
        // Arguments: IncidentParms parms
        // IncidentParms is an object defined as:
        //
        //public class IncidentParms : Saveable
        //{
        //    public Thing target;
        //    public float points = -1f;
        //    public float maxSquadCost = 99999f;
        //    public bool forceIncap;
        //    public void ExposeData()
        //    public override string ToString()
        //}
        //
        // TryExecute returns TRUE under any non-error outcome. Returning FALSE would indicate an error state.
public override bool TryExecute(IncidentParms parms)
{
            // Writes a line to the debugging log, visible ingame in developer mode.
Debug.Log("Test log");
Debug.Log("Map size is " + Find.get_Map().get_Size());
bool flag;
            // Uses a Linq (SQL-like) statement to find a random incapacitated Colonist Pawn.
            // The 'out flag' argument means that 'flag' will be set to TRUE if a colonist matching those conditions is found.
Pawn pawn = GenLinq.TryRandomElement<Pawn>(
from col in Find.get_ListerPawns().get_Colonists()
where col.get_Incapacitated()
select col, out flag);
            // If a random incapped pawn is selected:
if (flag)
{
                // Get the amount of missing health from the target, less between 2 and 10.
int num = pawn.healthTracker.get_MaxHealth() - pawn.healthTracker.get_Health() - UnityEngine.Random.Range(2, 10);
                // Heal the pawn by the determined amount.
                pawn.TakeDamage(new DamageInfo(DamageType.Healing, num));
                // Create a letter to be displayed to the player.
Letter letter = new Letter(pawn.get_Name().nick + " has experienced a miraculous recovery!", 1, pawn);
                // Deliver the newly created letter.
Find.get_LetterStack().ReceiveLetter(letter);

return true;
}

return true;
}
}
}

This code has been updated slightly, just according to some small suggestions from Visual Studio 2013.

So, would a game-wide commenting project like this of any use to anyone? Please let me know if you can clear up a few things I don't understand about the incident system, like how the storyteller picks incidents from the list of defined incidents.

Kilroy232

Nice, this is exactly what we need to begin to learn how to make more in depth mods. gj