RimWorld

RimWorld

Life Lessons
albinogod 2 May, 2024 @ 12:26pm
Question: Hediff patching.
I am sorry if you have answered this elsewhere, but with the current state of your framework is it possible to:

A) to set a proficiency to require a pawn to have a certain Hediff to be able to learn it?
B) to set a Hediff to passively give progress to learning a certain proficiency?

For context, I am working on a patch for a mod that your backstory autopatcher really doesn't like and is outside of your stated scope.
< >
Showing 1-11 of 11 comments
Wumpi  [developer] 2 May, 2024 @ 2:32pm 
My interpretation/understanding of your requirements:
1. You require the ability to prevent XP generation for a proficiency through any means unless the pawn has a specific hediff
2. You want the presence of a hediff itself to slowly generate XP towards a proficiency

My questions are
A. for requirement 1, would this hediff need to prevent learning from any source even if there are other sources of XP - for example, would it need to prevent XP from pioneering, recipe rewards, or neurotrainers? Or, is the intent that a new proficiency would be added that simply wouldn't configure those other sources?

Essentialy what I am trying to understand is whether it is just intended to be the sole source of learning, or if it is intended to explicitly prevent learning from any other source. One is configuration decision on your end, the other is a feature request on my end.

B. What, specifically, are you trying to accomplish - in game terms? What mod are you trying to patch? What is this hediff that generates XP, how is it applied or acquired, how does it work?

The patching utility (not an "auto" patcher, really,) doesn't cover hediff patches due to their complexity and relative rarity. The tool is just something to help save me keystrokes, so it was more time efficient to spend a few hours manually creating hediff patches than it was to spend a week or two creating an interface to do it for me.

I'm happy to add additional functionality if we can establish clear requirements on what is needed and how it should work.
albinogod 2 May, 2024 @ 3:47pm 
The mod series I am patching is the "A Rim Reborn" set. I have made a separate set of proficiencies and a few other minor things to get it to work while still keeping the "feel" of the mod and its source material. It only really needed the backstories to be manually patched to get it to generate pawns again, but I figured that I might as well do the whole thing while I was at it.

A) it is for a new proficiency that only the sources of XP is form being taught in a class. It is also set to not generate text books and neurotrainers. The Hediff (ARR_Aether) is applied to all the HAR races added by the series and is required to do any of the crafting and research from the mod series, allowing pawns without it would to learn the added proficiencies would feel a bit weird and likely mistaken as a bug once/if I publish the set of patches.

B) the Hediff in question (ARR_AnimaDrain) is applied after completing a certain job (patching the job directly did not work) or after a caravan interaction (both returning the pawn to a point on the colony map). It then lasts for a few days depending on the source and prevents the pawn from doing any other action that would apply it. Game play wise, I want it to serve as an alternative way to gain a proficiency after it has been pioneered or as an easier way to recover the knowledge of it if head researcher is lost.
Wumpi  [developer] 2 May, 2024 @ 7:58pm 
Alright, so after thinking it over:
1. I have added a new field to the proficiency def "conditions." Currently the only condition is hasHediff. The condition field represents a total lockout for learning of a proficiency - all conditions must be met before any XP can be generated, even if all prerequisites are met.

An example
<conditions>
<hasHediffs>
<li>SpeedBoost</li>
</hasHediffs>
</conditions>
There is a new section in the proficiency viewer info panel that describes these requirements - though thinking on it now we may need some additional tooltips for extra clarity.

2. I considered the idea of "learning via hediff" but as far as the core mod is concerned, I don't think it is really within the scope of what tools I want to provide. If I could foresee anywhere the core or sub mods might use something like that I could justify the cost of maintaining it going forward, but it's not something I think we'll ever get to use.

That said, the achieve this functionality as part of your patch would be pretty straight forward - an excellent first modding project if you're not familiar with the process.
Essentially you'd need:
1. A HediffComp class with HediffTick implemented to call our own ProficiencyComp.TryGainXP() method
2. An XML patch to add it to the hediff you want to modify
3. Add a customAcquisitionDescriptions entry to the proficiency def to describe how it can be earned by having the hediff

I'd be happy to help if you have questions for setting something like that up
Wumpi  [developer] 2 May, 2024 @ 7:59pm 
The conditions addon is pushed to the current steam version, so you can try that out and see if it accomplishes what you want
albinogod 2 May, 2024 @ 8:15pm 
Thank you for the fast turn around on my request. I will defiantly make attempt at adding the "teaching" hediff on my end once I get the rest of my patch to a publishable state. While this isn't my first modding project, it is a good excuse to finally do more than simple xml stuff.
albinogod 4 May, 2024 @ 10:29am 
Just a quick update. The hasHediff condition works perfectly for what i needed it for. I have a version ready for initial play testing, which should be starting later today. The only integrations that it is missing is for the Medical Module (currently not sure if it is even needed) and the Martial Module, which I will work on once you release it.

As for the new functionality. The only thing I am currently confused about is how to pass the HediffComp's attributes to your ProficiencyComp.TryGainXP() method. Feeding them in directly produces a CS0120 error (An object reference is required for the non-static field...). I have a feeling that I am missing something fundamental at this point since the possible fixes that I have found via Google seem to me to not be applicable to this situation.
Wumpi  [developer] 4 May, 2024 @ 12:30pm 
From a hediff comp, it would look something like
parentPawn.getcomp<ProficiencyComp>().TryGainXp(xpAmountPerTick, proficiencyDef, ExperienceType.Both)

If you post the entire stack trace I might be able to assist with that
albinogod 4 May, 2024 @ 1:38pm 
First I would like to apologized, I am still extremely new to C# let alone programming and this problem seems to come from that. I will have to more reading before I think I will be able to anything major in C#.

I hope this is what you are asking for, although I am not entirely sure.
HediffComp_teacher.cs(18,17,18,42): error CS0120: An object reference is required for the non-static field, method, or property 'ProficiencyComp.TryGainXp(float, ProficiencyDef, ExperienceType)'

This is the code for the code for the HediffComp, which I am pretty sure is likely going to need to be entirely reworked to function as I want.
public class HediffComp_teacher : HediffComp { public ProficiencyDef proficiency; public ExperienceType experienceType; public float learnrate = 1f; public HediffCompProperties_teacher Props => (HediffCompProperties_teacher)props; public override void CompPostTick(ref float severityAdjustment) { if (parent.Severity > 0f) { float xp = parent.Severity * Props.learnrate; ProficiencyComp.TryGainXp(xp, Props.proficiency, Props.experienceType); } } }
albinogod 4 May, 2024 @ 5:21pm 
Honestly, the more I think about this the more and the more I experiment with it the more I feel I should put this part of the project on hold until I have a workable understanding of what I am doing before trying to do anything in C#. But thank you for the bits of advice and encouragement that you have given me thus far. Hopefully I will be able to come back to this sooner than later.
Wumpi  [developer] 4 May, 2024 @ 5:41pm 
The best way to learn programming is to learn it by working on a specific project you have a personal interest in. Struggling through this issue will teach you 10x more than any tutorials or textbooks. Most people fail programming because they start with "I want to learn programming" rather than "I want to solve a problem that requires programming."
You're already better positioned than most college graduates just by nature of your problem statement.

As for the issue,
The "Stack trace" refers to the call "stack." The stack, in short, is the series of method or field references that lead the control of the program to the current point. For example, HediffComp_teacher's call to TryGainXP is one layer of the call stack. Your log should contain a larger error messages like below

Error in static constructor of Temp_MechJobFix.MechJobFix: System.TypeInitializationException: The type initializer for 'Temp_MechJobFix.MechJobFix' threw an exception. ---> System.TypeLoadException: Could not resolve type with token 01000016 (from typeref, class/assembly Rimefeller.WorkGiver_OperateResourceConsole, Rimefeller, Version=1.2.7137.27809, Culture=neutral, PublicKeyToken=null)
--- End of inner exception stack trace ---
at (wrapper managed-to-native) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(intptr)
at (wrapper dynamic-method) System.Runtime.CompilerServices.RuntimeHelpers.System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor_Patch1(System.RuntimeTypeHandle)
at (wrapper dynamic-method) Verse.StaticConstructorOnStartupUtility.Verse.StaticConstructorOnStartupUtility.CallAll_Patch1()
(Filename: C:\buildslave\unity\build\Runtime/Export/Debug/Debug.bindings.h Line: 39)

I'll need the entire message (or the entire log) to know more about where your issue occured.

That said, the actual issue is here:
ProficiencyComp.TryGainXp(xp, Props.proficiency, Props.experienceType);
You're using ProficiencyComp as though it were a static class, when it is not a static class. The error means that you need a reference - an instance of the class, rather than the static class. ProficiencyComp is a ThingComp, meaning it is attached to a Thing in the same way your HediffComp is attached to a Hediff.

Your hediff is attached to a pawn, and that pawn has a ProficiencyComp. You can obtain a reference by calling
parent.pawn.TryGetComp<ProficiencyComp>()

parent is a field from the base class HediffComp, and refers to the hediff. pawn is a field from hediff. TryGetComp is a generic method that will look up a comp of the specific type <ProficiencyComp>, and return it if it exists.
Not all pawns have a ProficiencyComp, so once you get your reference, it's important to do a null check

ProficiencyComp comp = parent.pawn.TryGetComp<ProficiencyComp>()

if (comp != null) {
Do stuff
}

You can also join the discord to (probably) get more prompt assistance. The Rimworld discord itself also has some modders who can help, but I cannot recommend it.
albinogod 4 May, 2024 @ 6:39pm 
While it seems I was on the right track as to why it wasn't working (just not how to fix it and why to fix it a certain way over another), your explanation is going to immeasurably help me with my future plans. I still plan on doing still plan to do some further reading to build up a better understanding of the fundamentals, but to correct a potential misunderstanding; this current project, Celsius Patches, and a few others that won't see the light of day are me trying to figure out what I didn't know that I don't know before I attempt a larger project that I want to and WILL make.

But I will stop bothering you until I find another novel edge case in your framework.
< >
Showing 1-11 of 11 comments
Per page: 1530 50