[Solved] Accessing currently selected pawn in starting pawn configuration screen

Started by Lakuna, April 09, 2020, 06:37:54 PM

Previous topic - Next topic

Lakuna

My problem:
I've been working at a smallish mod for about a week now and I've run into a bit of a roadblock. For this mod to work, I need to have access to the currently selected pawn on the starting pawn configuration page, but I can't find a good way to do so.

In the following code snippets, page is used to refer to the current instance of RimWorld.Page_ConfigureStartingPawns. I'm already using Harmony so any solutions which require it work perfectly for me.

I know that the page I need to work with is an instance of RimWorld.Page_ConfigureStartingPawns. I believe that the variable I want to access is page.curPawn, but it's private so I can't be sure and I can't access it anyway. There's a method called page.SelectPawn(Pawn c) that I would be able to take it from fairly easily, but it seems that it doesn't actually occur when the player selects a different pawn in the pawn list. Additionally, I am aware that I can get a list of the pawns from Find.GameInitData.startingAndOptionalPawns, but I need to be able to tell which pawn is currently selected (or at least which pawn is actively being randomized whenever a pawn is randomized). The method which randomizes pawns is page.RandomizeCurPawn(), which is what I'll eventually need to modify, but it doesn't reference the pawn being randomized except through page.curPawn. I'd prefer to avoid using reflection for obvious reasons, but if I must use it what is the best way to do so?

Context in case it's needed:
I'm making a mod which is intended as a replacement for EdB's Prepare Carefully - which is a great mod, but I've always wanted an alternative which still leaves some part of the pawns up to chance. This mod will allow the player to define a filter which pawns must meet at minimum. Then, whenever the player randomizes a pawn, the game will automatically re-randomize that pawn until they meet that filter. The repository can be found here on GitHub - although please note that since I've been working on this issue for a bit some parts of the code are temporary and not intended to be in the final product.

Thank you in advance.

EDIT: Formatting.

EDIT: I've already looked through the code for similar mods such as Prepare Carefully and Verify Start and am actively using them as reference. The problem with both examples is that they only access all colonists at once (which I already know how to do) rather than just the one that is selected.

EDIT: I found a way to make this work that I'm somewhat comfortable with by comparing names of pawns before randomizing to after, but I still feel like there must be a better way and would like to know if there is.

LWM

QuoteI believe that the variable I want to access is page.curPawn, but it's private so I can't be sure and I can't access it anyway.

There are several ways of doing this.

If you're already inside Harmony and have Page_ConfigureStartingPawns __instance, then if you declare Pawn ___curPawn (that's three '_'), Harmony will automagically link it to the private field.

If you're not inside Harmony, you can do what Harmony does and access via Reflection (you don't have to care about performance with what you're doing, so this should be fine):

FieldInfo curPawnField=HarmonyLib.AccessTools.Field(typeof(Page_C&c), "curPawn"); // let Harmony do some heavy lifting
Pawn curPawn=curPawnField.GetValue(page);

Magic!

--LWM

Lakuna

Thank you! I'm already in Harmony, so I can just do the triple underscore trick. It's odd to me that I didn't see this anywhere when I read through the documentation.

LWM

It's there!  ...somewhere ;)

https://harmony.pardeike.net/articles/patching-injections.html - "Private fields"

Yeah, the documentation isn't 100% easy to read, and it helps if you already know what you're looking for ><  To be fair, it's a fairly complicated tool, and the documentation is a lot better than it used to be...

Lakuna

Thank you for your help. I marked the post as solved (I had to remove the period at the end due to character limit ;-;)