Original calls x.foo() and foo gets passed to replacer1, replacer2 replacer3 who all have their chance to replace it with something else and in the end x.bar() is written. Here, multiple mods patching could register their replacers which would work in a chain: I want to add a replacer where you not only have prefix/postfix methods but also a way to replace methodbase A with B in the original method (since all IL codes are copied this is really trivial as long as A and B have the same call signature). Properties work too, just patch the "g(s)et_Property" method. Right now, it works with any kind of method unless inlined - I even got it to work with some anonymous subclass method where RimWorld originally defines a anonymous method to be used as a Predicate. It was a bit tricky to get the initial order of things working but once it works it works pretty flawless. Since I don't rely on subclassing and instead juggle arguments around, the whole thing becomes much more safe. constructing a wrapper in CIL that has the same signature as the original memory allocation and basic assembler handling for the initial redirect The critical and "unsafe" parts here are: Every time a prefix or postfix is added, the patch information is rewritten and a new wrapper is created.Īll the rest is just support stuff that is necessary to make this easy for the user. ![]() I then construct the wrapper to call all prefix methods, then the copy, then the postfix methods. Since I want to keep the original intact, I copy the IL codes of the target method to a copy. The first one to patch a targe method allocates this, everyone else that comes later simply reads the patch information, adds to it and replaces the patch information with a new version. Since every mod has its own class hierarchy this is necessary. In that memory area, I prefix the jump with a pointer to a byte array that deserializes to the patch information. There, I have a new jump to the replacement method (I call it a wrapper). So I allocate memory, add a jump from the jit code to that area (just like the old Detour). So for now, let me sketch the basic idea behind Harmony: Instead of having global state, I use the method that is to be patched (I call it the target method) to attach information. Raw already gave me a nice replacement for the memory allocation that I am about to test with my friend. So until I put up more details, I don't expect anybody to put anything into a something -)īut since the whole point is to build trust with the community, the only way forward is to put it out in the open and lab test it and gain insides. In the end, the current state is the result of lots of lessons learned. At one point, I even added my own csharp compiler and had dynamic source code in the project. The overall concept evolved around at least 10 different approaches which, by the nature of the problem, did not pan out in some way. I have a lot of internal documentation that probably is tl dr for many people so I have not put any effort into preparing them. I totally understand your point of view Fluffy. I will personally try to advertise Harmony in the Unity forums because as it is now, Harmony isn't RimWorld specific. We are about to incorporate this into all the major mods and general libs like HugsLib. I am available for any questions in this thread. Please also help spreading the word so we all finally get to a point where we don't sabotage each other with detours that create dependencies and force the user to load mods in certain orders (Harmony defines priorities and dependencies internally). Quick starter snippet including a patch to load a specific game on start: Please feel free to give it a try and come back with feedback. ![]() The github repository has a ready made version of the lib in dll form and you can either add it to your Assemblies folder (add reference and keep "Copy" on) or merge it with a tool like ILMerge into your own dll. It comes with some wiki documentation and there are many mods using it on GitHub too (HugsLib has it build in i.e.). I made it completely open source and hope that we all together can continue to evolve it. You can find out more about it on GitHub. It even works if more than one mod patches a method and it is not a mod itself which means that your users don't have to install it. ![]() It will allow you to add code to any method inside RimWorld or other mods. Harmony is a simple dll that you embed in your mods. The right way of patching code at runtime
0 Comments
Leave a Reply. |