C# Planet Generation: Where to hook generation of additional planet locations?

Started by Alistaire, November 04, 2015, 04:02:07 PM

Previous topic - Next topic

Alistaire

I decided to take upon me the task of generating additional locations on the planet map. I'm in the process of writing up a working example
however I ran into the following problem:

// RimWorld.Planet.WorldGenerator
public static void GenerateWorld()
{
Current.World = new World();
Current.World.info.size = WorldGenerationData.size;
Current.World.info.seedString = WorldGenerationData.seedString.ToLowerInvariant();
Rand.Seed = (GenText.StableStringHash(WorldGenerationData.seedString) ^ 4323276);
Current.World.info.name = RulePackDef.Named("NamerWorld").GenerateDefault_Name(null);
WorldGenerator_Grid.GenerateGridIntoCurrentWorld(WorldGenerationData.seedString.ToLowerInvariant());
FactionGenerator.GenerateFactionsIntoCurrentWorld();
Current.World.renderer.Notify_WorldChanged();
}


I want to add the line "LocationGenerator.GenerateLocationsIntoCurrentWorld();" after the FactionGenerator line and I have no idea how to
do this.

The generation has to go specifically there because I want locations to show up on the map gen screen. It has to be after the faction
generator since locations can be owned by factions.




I found that a certain method which might be associated with this is a Unity event, therefore a delegate and therefore possible to hook into:

// RimWorld.Planet.WorldRenderCam
public void OnPostRender()
{
this.renderMode.DrawWorldMeshes();
WorldFactionsRenderer.DrawWorldFactions();
}


Once again I'm not sure how exactly to go about doing that. I assume using a dummy thingDef with inspectorTabs will run a class which can
append above delegate with location drawing code, then with location generation code which would remove itself from the delegate after its
first call (doing something if no locations are generated on the map or skipping that when they were previously generated). I don't know if
this makes any sense or if there's better methods to draw locations and generate locations and I haven't tested the code because I'm not
even partially finished with the rest of the code base I need for the entire mod.




I'd really like the above stuff to be possible since counting on Tynan to make the first method a delegate seems kinda hopeless while he's stopped development for a while.

So the question is:

How do I generate locations on the planet map during map generation?
..... or .....
How do I add a method call in RimWorld.Planet.WorldGenerator.GenerateWorld() ?

At least I assume it is. Thanks for reading!

Mmgfrcs

First off, It's quite internal. You would need to break the game's main DLL to do such thing
Even if you do managed to create the code, the game would call the old method instead. This will be a tough process to go

Second off, you will render the game unplayable. The world grid needs to be available first before factions could be placed properly: This is a C# and Unity base rules to programmers.

I don't have enough C# capabilities for this, but calling the delegate is not enough: it's just injecting your code

Alistaire

First off mods introduce additional assemblies which are loaded by the main game assembly so it's impossible for me to break the main game
assembly unless I somehow modify the conscious DLL file in my assembly. My question is not what to write to generate the locations, my
question is if I had finished that code where would I hook it into which implies I want to override the old method to begin with.

Second off if your solutions make the game unplayable they're not solutions - this request implies I want it to work which could be expected.
If I was doing this for pure theoretical entertainment or whatever I wouldn't have asked how to do it in the help subforum. I don't know where
you got the "world grid" from but the data type of Current.World is actually World and as you can see it's defined inside of the first method in
OP so it is available inside that method and it's certainly available after generation of the factions. I'm not trying to generate additional factions
I'm trying to generate "locations" which are a new data type, new Def type and new DefClass and Class specifically made for my mod. It's
completely irrelevant how I want to make them since it can't be hard as the Faction code is a pretty good copy paste target for it. I'm also
conscious that things have to be available before I can use it, this is a quite advanced C# request and it can be assumed that I know what I'm
talking about to sufficient extent.

I'm also not calling the delegate I'm adding delegates to it as described in the Unity documentation on Unity events such as OnPostRender().
This is not injection, you don't have to inject delegates. I must say I can't tell you in detail about this since I haven't worked with them
extensively which is partially why I posted this request.

RawCode

read this
https://ludeon.com/forums/index.php?topic=16774.0

if you want to pass control into other method, use jump or longjump opcodes and pointer to your method.

this is not "just DLL", you must use hacks in order to override methods not designed for this


Alistaire

I don't know what you're trying to explain but could you please give an example in the context of hooking into GenerateWorld()?

RawCode

you get function pointer of method you like to modify

inject call instruction
insert 4 bytes of relative offset from jump instruction to function pointer you like
insert leave instruction
insert return instruction

instead of real method, game will pass control into your code

negative jump offset have "complicated" calculation method, you can read about that from google "call near negative offset"

Alistaire

Quote from: RawCode on November 06, 2015, 12:38:08 AM
you get function pointer of method you like to modify

inject call instruction
insert 4 bytes of relative offset from jump instruction to function pointer you like
insert leave instruction
insert return instruction

instead of real method, game will pass control into your code

negative jump offset have "complicated" calculation method, you can read about that from google "call near negative offset"

And how do I translate this into code, where do I write this code (same assembly as the rest or what), when do I call this code and how do I call
this code at that point in time? I get that it's complicated but I don't have to learn this for an exam, how do I use it?

RawCode


Alistaire

I'd appreciate it if anyone was able to actually give a full fledged code example which explains what the practical use of above stuff is and how
I would implement it through examples with actual code in this specific situation (OP) so I don't have to keep getting repeat answers linking to
a forum thread full of whatever jargon it is trying to be.

Alistaire

For reference: I started breaking apart EdB Prepare Carefully to continue work on a working example. The above methods were discarded because it would take too much time to work out how to implement them.

RawCode

then just replace "select world" button.

EdB uses singleton method for loading, mod based of it will be incompatible with anything that use similar routine.

Alistaire

Quote from: RawCode on November 08, 2015, 10:43:33 AM
then just replace "select world" button.

EdB uses singleton method for loading, mod based of it will be incompatible with anything that use similar routine.

I have no idea how to do anything you mentioned before so if you're able to replace the select world button please just post the exact code you
used to do it. Currently it feels like you're expecting me to learn all this stuff but this is merely a code request.

I'm aware using the EdB method will make the mod incompatible with many others but that code is at least readily accessible and implementable.

RawCode

It's harmful in longterm to spoonfeed, at least without giving you a chance to do it self.

If you are perfectly sure "i want to skip everything give me code right now" - download EdB prepare carefully and "jet brains dot peek" then decompile EdB and open ModController and ModInitializer classes.

All you need is inside given classes.

Alistaire

Quote from: RawCode on November 09, 2015, 01:49:04 AM
It's harmful in longterm to spoonfeed, at least without giving you a chance to do it self.

If you are perfectly sure "i want to skip everything give me code right now" - download EdB prepare carefully and "jet brains dot peek" then decompile EdB and open ModController and ModInitializer classes.

All you need is inside given classes.

That's literally what I did, I wrote the modding tutorials wiki page. Could you stop talking down on me on a topic not only clearly detailing the
information one might need to help but also explicitly asking you to explain how anyone is supposed to do anything with the method you
provided to do... what exactly?

"I started breaking apart EdB Prepare Carefully" doesn't mean "I have no idea what I'm doing please help", EdB PC has a large code base and
it's built for a specific purpose which my mod doesn't fit and therefore along with tailoring the code to my needs I also have to write up the
code base that isn't readily provided. Do I really have to tell you that this many posts into a question that assumes I know what I'm doing? Apparently.

Again I'm not going to investigate your code cause I won't investigate how to write complex C# methods into assembly code. The fact that you
haven't answered any of my questions regarding the code that apparently does it all really doesn't give me any reason to start learning how it
works.

Alistaire

More reference: Using EdB's ITab method of replacing menus, which is something several mods including all EdB mods and CCL do, introduces no compatibility problems whatsoever.