Skip to content

Commit

Permalink
Refactored and optimize fast reroll algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
tea committed Jul 25, 2021
1 parent 68df93c commit 9625e6d
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 110 deletions.
92 changes: 5 additions & 87 deletions Source/HarmonyPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ static void Postfix()
[HarmonyPatch(typeof(Page_ConfigureStartingPawns), "RandomizeCurPawn")]
class Patch_RandomizeMethod
{
static FieldInfo curPawnFieldInfo;
static MethodInfo randomAgeMethodInfo;
static MethodInfo randomTraitMethodInfo;
static MethodInfo randomSkillMethodInfo;
static MethodInfo randomHealthMethodInfo;

static bool rerolling;

[HarmonyPrefix]
Expand Down Expand Up @@ -88,13 +82,13 @@ static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> inst

if (startIndex != -1)
{
var randomLimitRerollMethodInfo = typeof(RandomSettings)
.GetMethod("RandomRerollLimit", BindingFlags.Public | BindingFlags.Static);
//var randomLimitRerollMethodInfo = typeof(RandomSettings)
// .GetMethod("RandomRerollLimit", BindingFlags.Public | BindingFlags.Static);

var CheckPawnIsSatisfiedMethodInfo = typeof(RandomSettings)
.GetMethod("CheckPawnIsSatisfied", BindingFlags.Public | BindingFlags.Static);
//var CheckPawnIsSatisfiedMethodInfo = typeof(RandomSettings)
// .GetMethod("CheckPawnIsSatisfied", BindingFlags.Public | BindingFlags.Static);

var RerollMethodInfo = typeof(Patch_RandomizeMethod)
var RerollMethodInfo = typeof(RandomSettings)
.GetMethod("Reroll", BindingFlags.Public | BindingFlags.Static);

var startLoopLocation = codes[startIndex + 16].operand;
Expand All @@ -110,82 +104,6 @@ static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> inst

return codes;
}

public static bool Reroll(Pawn pawn)
{
if (RandomSettings.PawnFilter.RerollAlgorithm == PawnFilter.RerollAlgorithmOptions.Normal
|| RandomSettings.randomRerollCounter == 0)
{
return RandomSettings.CheckPawnIsSatisfied(pawn);
}

if (curPawnFieldInfo == null)
curPawnFieldInfo = typeof(Page_ConfigureStartingPawns)
.GetField("curPawn", BindingFlags.NonPublic | BindingFlags.Instance);

if (randomAgeMethodInfo == null)
randomAgeMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateRandomAge", BindingFlags.NonPublic | BindingFlags.Static);

if (randomTraitMethodInfo == null)
randomTraitMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateTraits", BindingFlags.NonPublic | BindingFlags.Static);

if(randomSkillMethodInfo == null)
randomSkillMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateSkills", BindingFlags.NonPublic | BindingFlags.Static);

if(randomHealthMethodInfo == null)
randomHealthMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateInitialHediffs", BindingFlags.NonPublic | BindingFlags.Static);

PawnGenerationRequest request = new PawnGenerationRequest(
Faction.OfPlayer.def.basicMemberKind,
Faction.OfPlayer,
PawnGenerationContext.PlayerStarter,
forceGenerateNewPawn: true,
mustBeCapableOfViolence: TutorSystem.TutorialMode,
colonistRelationChanceFactor: 20f);

if (!RandomSettings.CheckGenderIsSatisfied(pawn))
return false;

while (RandomSettings.randomRerollCounter <= RandomSettings.PawnFilter.RerollLimit)
{
pawn.ageTracker = new Pawn_AgeTracker(pawn);
pawn.story.traits = new TraitSet(pawn);
pawn.skills = new Pawn_SkillTracker(pawn);

randomAgeMethodInfo.Invoke(null, new object[] { pawn, request });
PawnBioAndNameGenerator.GiveAppropriateBioAndNameTo(pawn, pawn.story.birthLastName, request.Faction.def, request.ForceNoBackstory);
randomTraitMethodInfo.Invoke(null, new object[] { pawn, request });
randomSkillMethodInfo.Invoke(null, new object[] { pawn });

for (int i = 0; i < 100; i++)
{
pawn.health = new Pawn_HealthTracker(pawn);
try
{
randomHealthMethodInfo.Invoke(null, new object[] { pawn, request });
if (!(pawn.Dead || pawn.Destroyed || pawn.Downed))
break;
}
catch (Exception)
{
Find.WorldPawns.RemoveAndDiscardPawnViaGC(pawn);
return false;
}
}

pawn.workSettings.EnableAndInitialize();

//RandomSettings.randomRerollCounter++;

if (RandomSettings.CheckPawnIsSatisfied(pawn))
return true;
}
return false;
}
}

// working progress
Expand Down
183 changes: 160 additions & 23 deletions Source/RandomSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

namespace RandomPlus
{
Expand Down Expand Up @@ -45,6 +46,102 @@ public static void ResetRerollCounter()
randomRerollCounter = 0;
}

static FieldInfo curPawnFieldInfo;
static MethodInfo randomAgeMethodInfo;
static MethodInfo randomTraitMethodInfo;
static MethodInfo randomSkillMethodInfo;
static MethodInfo randomHealthMethodInfo;
public static bool Reroll(Pawn pawn)
{
if (PawnFilter.RerollAlgorithm == PawnFilter.RerollAlgorithmOptions.Normal
|| randomRerollCounter == 0)
{
return CheckPawnIsSatisfied(pawn);
}

if (curPawnFieldInfo == null)
curPawnFieldInfo = typeof(Page_ConfigureStartingPawns)
.GetField("curPawn", BindingFlags.NonPublic | BindingFlags.Instance);

if (randomAgeMethodInfo == null)
randomAgeMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateRandomAge", BindingFlags.NonPublic | BindingFlags.Static);

if (randomTraitMethodInfo == null)
randomTraitMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateTraits", BindingFlags.NonPublic | BindingFlags.Static);

if (randomSkillMethodInfo == null)
randomSkillMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateSkills", BindingFlags.NonPublic | BindingFlags.Static);

if (randomHealthMethodInfo == null)
randomHealthMethodInfo = typeof(PawnGenerator)
.GetMethod("GenerateInitialHediffs", BindingFlags.NonPublic | BindingFlags.Static);

PawnGenerationRequest request = new PawnGenerationRequest(
Faction.OfPlayer.def.basicMemberKind,
Faction.OfPlayer,
PawnGenerationContext.PlayerStarter,
forceGenerateNewPawn: true,
mustBeCapableOfViolence: TutorSystem.TutorialMode,
colonistRelationChanceFactor: 20f);

if (!CheckGenderIsSatisfied(pawn))
{
randomRerollCounter++;
return false;
}

while (randomRerollCounter < PawnFilter.RerollLimit)
{
randomRerollCounter++;

pawn.ageTracker = new Pawn_AgeTracker(pawn);
randomAgeMethodInfo.Invoke(null, new object[] { pawn, request });
if (!CheckAgeIsSatisfied(pawn))
continue;

pawn.story.traits = new TraitSet(pawn);
pawn.skills = new Pawn_SkillTracker(pawn);
PawnBioAndNameGenerator.GiveAppropriateBioAndNameTo(pawn, pawn.story.birthLastName, request.Faction.def, request.ForceNoBackstory);
randomTraitMethodInfo.Invoke(null, new object[] { pawn, request });
randomSkillMethodInfo.Invoke(null, new object[] { pawn });
if (!CheckSkillsIsSatisfied(pawn) || !CheckTraitsIsSatisfied(pawn))
continue;

for (int i = 0; i < 100; i++)
{
pawn.health = new Pawn_HealthTracker(pawn);
try
{
randomHealthMethodInfo.Invoke(null, new object[] { pawn, request });
if (!(pawn.Dead || pawn.Destroyed || pawn.Downed))
break;
}
catch (Exception)
{
Find.WorldPawns.RemoveAndDiscardPawnViaGC(pawn);
return false;
}
}
if (!CheckHealthIsSatisfied(pawn))
continue;

pawn.workSettings.EnableAndInitialize();
if (!CheckWorkIsSatisfied(pawn))
continue;

return true;
}

if (RandomRerollCounter() >= PawnFilter.RerollLimit)
{
return true;
}
return false;
}

public static bool CheckPawnIsSatisfied(Pawn pawn)
{
if (RandomRerollCounter() >= PawnFilter.RerollLimit)
Expand All @@ -56,16 +153,56 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
if (!CheckGenderIsSatisfied(pawn))
return false;

if (!CheckSkillsIsSatisfied(pawn))
return false;

if (!CheckTraitsIsSatisfied(pawn))
return false;

if (!CheckHealthIsSatisfied(pawn))
return false;

if (!CheckWorkIsSatisfied(pawn))
return false;

if (!CheckAgeIsSatisfied(pawn))
return false;

return true;
}

public static bool CheckAgeIsSatisfied(Pawn pawn)
{
if (pawnFilter.ageRange.min != PawnFilter.MinAgeDefault ||
pawnFilter.ageRange.max != PawnFilter.MaxAgeDefault)
{
if (pawnFilter.ageRange.min > pawn.ageTracker.AgeBiologicalYears ||
(pawnFilter.ageRange.max != PawnFilter.MaxAgeDefault && pawnFilter.ageRange.max < pawn.ageTracker.AgeBiologicalYears))
return false;
}
return true;
}

public static bool CheckGenderIsSatisfied(Pawn pawn)
{
if (pawnFilter.Gender != Gender.None && pawn.gender != Gender.None)
if (pawnFilter.Gender != pawn.gender)
return false;
return true;
}

public static bool CheckSkillsIsSatisfied(Pawn pawn)
{
List<SkillRecord> skillList = pawn.skills.skills;
foreach (var skillFilter in pawnFilter.Skills)
{
if (skillFilter.Passion != Passion.None ||
if (skillFilter.Passion != Passion.None ||
skillFilter.MinValue > 0)
{
var skillRecord = skillList.FirstOrDefault(i => i.def == skillFilter.SkillDef);
if (skillRecord != null)
{
if (skillRecord.passion < skillFilter.Passion ||
if (skillRecord.passion < skillFilter.Passion ||
skillRecord.Level < skillFilter.MinValue)
{
return false;
Expand All @@ -90,6 +227,11 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
}
}

return true;
}

public static bool CheckTraitsIsSatisfied(Pawn pawn)
{
// handle required and exclude traits
var traitFilterList = pawnFilter.Traits;
foreach (var traitContainer in traitFilterList)
Expand All @@ -110,12 +252,13 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
}

// handle trait pool (optional)
if (pawnFilter.RequiredTraitsInPool > 0 &&
if (pawnFilter.RequiredTraitsInPool > 0 &&
pawnFilter.RequiredTraitsInPool <= pawnFilter.Traits.Count())
{
int pawnHasTraitCounter = 0;
var traitPool = pawnFilter.Traits.Where(t => t.traitFilter == TraitContainer.TraitFilterType.Optional);
foreach (var traitContainer in traitPool) {
foreach (var traitContainer in traitPool)
{
if (HasTrait(pawn, traitContainer.trait))
{
pawnHasTraitCounter++;
Expand All @@ -127,8 +270,14 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
return false;
}

return true;
}

public static bool CheckHealthIsSatisfied(Pawn pawn)
{
// handle health options
switch (pawnFilter.FilterHealthCondition) {
switch (pawnFilter.FilterHealthCondition)
{
case PawnFilter.HealthOptions.AllowAll:
break;
case PawnFilter.HealthOptions.OnlyStartCondition:
Expand All @@ -151,9 +300,14 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
return false;
break;
}
return true;
}

public static bool CheckWorkIsSatisfied(Pawn pawn)
{
// handle work options
switch (pawnFilter.FilterIncapable) {
switch (pawnFilter.FilterIncapable)
{
case PawnFilter.IncapableOptions.AllowAll:
break;
case PawnFilter.IncapableOptions.NoDumbLabor:
Expand All @@ -165,23 +319,6 @@ public static bool CheckPawnIsSatisfied(Pawn pawn)
return false;
break;
}

if (pawnFilter.ageRange.min != PawnFilter.MinAgeDefault ||
pawnFilter.ageRange.max != PawnFilter.MaxAgeDefault)
{
if (pawnFilter.ageRange.min > pawn.ageTracker.AgeBiologicalYears ||
(pawnFilter.ageRange.max != PawnFilter.MaxAgeDefault && pawnFilter.ageRange.max < pawn.ageTracker.AgeBiologicalYears))
return false;
}

return true;
}

public static bool CheckGenderIsSatisfied(Pawn pawn)
{
if (pawnFilter.Gender != Gender.None && pawn.gender != Gender.None)
if (pawnFilter.Gender != pawn.gender)
return false;
return true;
}

Expand Down

0 comments on commit 9625e6d

Please sign in to comment.