Pawn generation dll?

Started by Em, May 24, 2016, 01:34:41 PM

Previous topic - Next topic

Em

In what dll is the script for pawn generation? I haven't found a dll where GenerationChance was actually used.

Where are the colonists generated?

And how do I decompile the dlls without getting:
// ISSUE: reference to a compiler-generated field

1000101

GenerationChance is used in a lot of places.  Do a search in Assembly-CSharp.dll for references.

Colonists generation is handled like anything else by the map generator.  Look in the /Mods/Core/Defs/MapGeneratorDefs for the xml and in the C# class Genstep_Colonists.

As to decompiling and the compiler-generated fields/classes/code - That is unavoidable.  You will need to use the computer between your ears to reverse engineer those.  They are generally the result of enumerable returns (ie, a function is declared as IEnumerable<Type> and uses yield return object).  Some decompilers handle those better than others, but the two big ones (IlSpy and dotPeek) don't handle them very well.
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

Fluffy (l2032)

I've had some mixed success with Telerik JustDecompile, but yeah, they're kinda screwed up. Note that you might have to set a checkbox in the options anywhere to toggle decompilation of compiler generated blocks/enumerator blocks or something along those lines. Confusingly, in ILSpy the toggle is reversed (e.g. it works if it's off).

One piece of advice, you generally get a MoveNext() function in the decompiled IEnumerator. While you can't copy/paste this directly, in 95% of cases you can reconstruct the logic of the block from MoveNext.

Em

I have just noticed that the family relationships are set by the parent direct relation. So, sibling, half sibling etc must be calculated at all times I think. Does anyone know where that happens? I'd like to change up some things.

I still don't understand how exactly I replace code, instead of creating new ones. I mean, I'd have to replace the whole dll file, but we can't get the whole dll file because it always generates missing lines.

1000101

You don't need to replace the whole dll, you only need to override certain parts.  However, parts which aren't linked via xml (ie, those directly referenced in the dll) will need to be detoured.  CCL provides a detouring mechanism so all you need to do is write the replacement method and an injector (SpecialInjector) to do the actual detour.
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

Em

Oh god, I think that goes beyond my coding capabilites. So, how exactly do I override certain parts?

1000101

It's actually not very hard at all.  If you can write the method you need then you are already 90% there.  Just make sure the method prototype matches (that is, the line which defines the parameters and return type).

The "SpecialInjector" is just a class in CCL which you inherit, it has an abstract bool "Inject()" method which you implement (write) and does the work to "detour" (calls TryDetourFromTo()) the original method with your own. When you get that far we can discuss it more.

For now, worry about the methods you want to replace and writing the methods you need to replace them with.
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

joaonunes

Quote from: 1000101 on May 24, 2016, 03:14:00 PM
GenerationChance is used in a lot of places.  Do a search in Assembly-CSharp.dll for references.

Colonists generation is handled like anything else by the map generator.  Look in the /Mods/Core/Defs/MapGeneratorDefs for the xml and in the C# class Genstep_Colonists.

As to decompiling and the compiler-generated fields/classes/code - That is unavoidable.  You will need to use the computer between your ears to reverse engineer those.  They are generally the result of enumerable returns (ie, a function is declared as IEnumerable<Type> and uses yield return object).  Some decompilers handle those better than others, but the two big ones (IlSpy and dotPeek) don't handle them very well.

Sorry to change the subject of this post, but you said that you didn't help me after I placed you in the credits for my mod. Now you DID help me, by telling me where to find the code to generate the heads for the pawns :D Now I have two options:
- Remove the random selector that's on that file and get the chance values from a xml;
- Edit the code to select two images instead of one, head and mustache, each with it's own list, and then merge both textures. I prefer this option even though it is a bit harder :D
Do you want your colonists to look manlier?
Get a free mustache sample here!

Fluffy (l2032)

let me stop you right there - you can't combine textures dynamically. Unity loads textures directly into the GPU by default, meaning you can't read or write pixel data. (There are ways around this; code-created textures (e.g. the minimap overlay) dont suffer this restriction, and you can use a RenderCamera to render onto a texture. The first won't work for art, the second is rather complex.)

What you could potentially do is create a new Graphics class, which is basically the container RimWorld uses that holds graphics data and it's rendering methods. I think you might be able to extent the class, add another texture, and change the draw methods to draw both textures. I've never tried anything like this, but it might be your best bet.

joaonunes

#9
Quote from: Fluffy (l2032) on May 30, 2016, 04:03:03 AM
let me stop you right there - you can't combine textures dynamically. Unity loads textures directly into the GPU by default, meaning you can't read or write pixel data. (There are ways around this; code-created textures (e.g. the minimap overlay) dont suffer this restriction, and you can use a RenderCamera to render onto a texture. The first won't work for art, the second is rather complex.)

What you could potentially do is create a new Graphics class, which is basically the container RimWorld uses that holds graphics data and it's rendering methods. I think you might be able to extent the class, add another texture, and change the draw methods to draw both textures. I've never tried anything like this, but it might be your best bet.

I have reached the same conclusion and tried to find another way around, but I am afraid that is not possible... I have no choice :/
To merge the textures I would basically either overwrite or create pawn heads instead of layering them dynamically, doing the exact same thing I did before, only by editorc# instead of an image editor.
That class is overwelming and I am afraid that wont be the only thing I'll need to change, but since I've been trying to avoid it I can't really say :P

Thanks once again, good to know someone else is following my steps (would be a bit creepy IRL though xD)

EDIT: I think we were talking about different classes :P Did you mean the "UnityEngine.Graphics"?
Do you want your colonists to look manlier?
Get a free mustache sample here!

Fluffy (l2032)

What I was referring to was Verse.Graphic. As you can see in a decompiler, that's the base class used for pretty much all rendering - there's various inherited classes with extra functionality (e.g. Graphic_Multi, Graphic_Random, etc etc.).

Since I've had to boot up a decompiler to look at this myself, I did ran into some other potential issues - namely that these classes are all for Things. E.g., apparel, pawns, buildings, anything that has a 'physical' representation in the game. This is not normally the case for facial hair, so you'd have to somehow add that in - or go with a different route. That said, using facial hair as a thing could potentially open the way for facial hair that actually grows, which would be cool :P.

joaonunes

using hair as a wearable thing that you cant wear, like a default non-removable hat?

jesus...

Don't get me wrong, I love the idea, but it looks like it gets more complicated the further I go xD

I checked the code for rendering the pawns and found out that a lot of code I could edit is located in the class "PawnGraphicsSet" or something like that, but have no idea on how to add it because the only mechanics that currently exist and I could adapt would be either the heads or hair rendering, and that thing is a mess... It would probably be better to use beards and mustaches as wearable clothes that can't be removed, at least that way the only thing that would have would be maybe a "unremovable" tag or something... I'll need a bit more research, but so far it seems to be easier to implement, plus it could also open doors to hair growth xD
Do you want your colonists to look manlier?
Get a free mustache sample here!

Fluffy (l2032)

Yeah, tacking it on as a 'plugin' means you don't need to muck about with actual pawn rendering code, which is a huge plus. First off because that shit is complicated and you're more likely than not to break something, and second because messing with pawn code is never a good idea from a compatibility point of view.

I'm just spitballing here, but I believe comps also have a PostRender or PostDraw virtual method, do they not? You might be able to do this through a comp. I would probably try to still have facial hair be a Thing class object, attach it to the comp, then use one of the Graphics child classes to do the rendering from within the comp's post draw method. That way the actual facial hair thing is in the comp, so can't be unequipped, but you should be able to re-use the thing drawing code. (This is without having the code open, so this may not be possible at all).

joaonunes

Yeah. For the thing to be properly done the hair would be added to the PawnGraphicSet (rebuild the class...) and rendered properly through the renderer (rebuild a couple of methods) and it would make this mod incompatible with almoat everything that adds hairs or faces unless I took extra care...
Do you want your colonists to look manlier?
Get a free mustache sample here!

Em

#14
I still haven't found the class that sets the relationships. I know there has to be a loop that checks:
If  (father of pawn 1 == father of pawn 2 && if mother of pawn 1 == mother of pawn 2){
setrelationship= siblings}

Something like that. No idea where it is =(


Oh and another little thing:
Where do I find the getPawn command? If I want to get an existing pawn from the global pawn list? I found a list MapPawns, but it has no simple getPawn(Name x) or whatever. I don't get it. =(