Skip to content

Commit

Permalink
Null ref checking + placeholder code
Browse files Browse the repository at this point in the history
v1.0.9.12 (June 1st, 2018)
=====================
- Added more null reference checking and handling to PawnShields
  • Loading branch information
jecrell committed Jun 1, 2018
1 parent c1db649 commit 6a814ce
Show file tree
Hide file tree
Showing 16 changed files with 772 additions and 1,525 deletions.
2 changes: 1 addition & 1 deletion About/About.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<url>https://discord.gg/AaVFA7V</url>
<targetVersion>0.18.0</targetVersion>
<description>
[1.0.9.11] (May 2018)
[1.0.9.12] (June 2018)
Adds modding components to RimWorld: vehicles, spell casting, weapon slots, oversized weapons, and more!

Note to players: This mod will not change your game, but rather it lets modders do more, so you can have an even more amazing RimWorld experience.
Expand Down
Binary file modified Assemblies/0JecsTools.dll
Binary file not shown.
Binary file modified Assemblies/AbilityUserAI.dll
Binary file not shown.
Binary file modified Assemblies/CompInstalledPart.dll
Binary file not shown.
Binary file modified Assemblies/CompSlotLoadable.dll
Binary file not shown.
Binary file modified Assemblies/PawnShields.dll
Binary file not shown.
3 changes: 2 additions & 1 deletion Source/.idea/.idea.JecsTools/.idea/contentModel.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2,088 changes: 607 additions & 1,481 deletions Source/.idea/.idea.JecsTools/.idea/workspace.xml

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Source/AllModdingComponents/JecsTools/HarmonyPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace JecsTools
{
[StaticConstructorOnStartup]
public static class HarmonyPatches
public static partial class HarmonyPatches
{
//For alternating fire on some weapons
public static Dictionary<Thing, int> AlternatingFireTracker = new Dictionary<Thing, int>();
Expand Down Expand Up @@ -46,6 +46,8 @@ static HarmonyPatches()
// new HarmonyMethod(type, nameof(IsNaked)), null);
harmony.Patch(AccessTools.Method(typeof(PawnApparelGenerator), "GenerateStartingApparelFor"), null,
new HarmonyMethod(type, nameof(GenerateStartingApparelFor)), null);

//GUIPatches(harmony);
}


Expand Down
90 changes: 90 additions & 0 deletions Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection.Emit;
using AbilityUser;
using Harmony;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.Sound;

namespace JecsTools
{
public static partial class HarmonyPatches
{
private static bool drawButtonsPatched;

public static void GUIPatches(HarmonyInstance harmony)
{
//Allow fortitude to soak damage
var type = typeof(HarmonyPatches);
harmony.Patch(AccessTools.Method(typeof(DebugWindowsOpener), "DrawButtons"), null,
null, new HarmonyMethod(type, nameof(DrawAdditionalButtons)));
harmony.Patch(AccessTools.Method(typeof(MoteMaker), "MakeMoodThoughtBubble"), null,
new HarmonyMethod(type, nameof(ToggleMoodThoughtBubble)),
null);
}

public static void ToggleMoodThoughtBubble(Pawn pawn, Thought thought, ref MoteBubble __result)
{
if (!bubblesEnabled) __result = null;
}

public static IEnumerable<CodeInstruction> DrawAdditionalButtons(IEnumerable<CodeInstruction> instructions) {
var instructionsArr = instructions.ToArray();
var widgetRowIndex = TryGetLocalIndexOfConstructedObject(instructionsArr, typeof(WidgetRow));
foreach (var inst in instructionsArr) {
if (!drawButtonsPatched && widgetRowIndex >= 0 && inst.opcode == OpCodes.Bne_Un) {
yield return new CodeInstruction(OpCodes.Ldloc, widgetRowIndex);
yield return new CodeInstruction(OpCodes.Call, ((Action<WidgetRow>)HarmonyPatches.DrawDebugToolbarButton).Method);
drawButtonsPatched = true;
}
yield return inst;
}
}

private static int TryGetLocalIndexOfConstructedObject(IEnumerable<CodeInstruction> instructions, Type constructedType, Type[] constructorParams = null) {
var constructor = AccessTools.Constructor(constructedType, constructorParams);
int localIndex = -1;
if (constructor == null) {
Log.Message($"Could not reflect constructor for type {constructedType}: {Environment.StackTrace}");
return localIndex;
}
CodeInstruction prevInstruction = null;
foreach (var inst in instructions) {
if (prevInstruction != null && prevInstruction.opcode == OpCodes.Newobj && constructor.Equals(prevInstruction.operand)) {
if (inst.opcode == OpCodes.Stloc_0) {
localIndex = 0;
} else if (inst.opcode == OpCodes.Stloc_1) {
localIndex = 1;
} else if (inst.opcode == OpCodes.Stloc_2) {
localIndex = 2;
} else if (inst.opcode == OpCodes.Stloc_3) {
localIndex = 3;
} else if (inst.opcode == OpCodes.Stloc && inst.operand is int) {
localIndex = (int)inst.operand;
}
if (localIndex >= 0) break;
}
prevInstruction = inst;
}
if (localIndex < 0) {
Log.Message($"Could not determine local index for constructed type {constructedType}: {Environment.StackTrace}");
}
return localIndex;
}

private static bool bubblesEnabled = true;
internal static void DrawDebugToolbarButton(WidgetRow widgetRow) {
if (Current.ProgramState == ProgramState.Playing)
{
widgetRow.ToggleableIcon(ref bubblesEnabled, TexButton.quickstartIconTex, "Toggle thought/speech bubbles.", null, null);
}
}



}
}
2 changes: 2 additions & 0 deletions Source/AllModdingComponents/JecsTools/JecsTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="FactionStuff\JobDefMaker.cs" />
<Compile Include="FactionStuff\JobDriver_UseConsole.cs" />
<Compile Include="FactionStuff\JecsToolsFactionDialogMaker.cs" />
<Compile Include="HarmonyPatches_GUI.cs" />
<Compile Include="HediffExpandedDef.cs" />
<Compile Include="HediffGiver_StartWithHediff.cs" />
<Compile Include="HediffWithComps_Expanded.cs" />
Expand All @@ -101,6 +102,7 @@
<Compile Include="Hediff_InjuryCustomLabel.cs" />
<Compile Include="PlaceWorker_OnTopOfWalls.cs" />
<Compile Include="ModCompatibilityUtility.cs" />
<Compile Include="TexButton.cs" />
<Compile Include="ThingDef_LaserProjectile.cs" />
<Compile Include="_HumanlikeOrdersUtility.cs" />
<Compile Include="JobGiver_AIFirelessTrashColonyClose.cs" />
Expand Down
13 changes: 13 additions & 0 deletions Source/AllModdingComponents/JecsTools/TexButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using UnityEngine;
using Verse;

namespace JecsTools
{
[StaticConstructorOnStartup]
internal class TexButton
{
public static readonly Texture2D quickstartIconTex = ContentFinder<Texture2D>.Get("quickstartIcon");

}
}
3 changes: 2 additions & 1 deletion Source/AllModdingComponents/PawnShields/HarmonyPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ static HarmonyPatches()

public static void Patch_PawnGenerator_GenerateGearFor(Pawn pawn, ref PawnGenerationRequest request)
{
PawnShieldGenerator.TryGenerateShieldFor(pawn, request);
if (pawn != null)
PawnShieldGenerator.TryGenerateShieldFor(pawn, request);
}

public static float StatWorkerInjection_AddShieldValue(Pawn pawn, StatDef stat)
Expand Down
2 changes: 1 addition & 1 deletion Source/AllModdingComponents/PawnShields/PawnShields.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>D:\SteamLibrary\steamapps\common\RimWorld\ModsWorkspace\JecsTools\Assemblies</OutputPath>
<OutputPath>C:\Program Files (x86)\Steam\steamapps\common\RimWorld\ModsWorkspace\JecsTools\Assemblies</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,94 +29,106 @@ public static class PawnShieldGenerator
public static void TryGenerateShieldFor(Pawn pawn, PawnGenerationRequest request)
{
//Shield stuff.
ShieldPawnGeneratorProperties generatorProps = request.KindDef.GetModExtension<ShieldPawnGeneratorProperties>();
ShieldPawnGeneratorProperties generatorProps =
request.KindDef?.GetModExtension<ShieldPawnGeneratorProperties>();

//Abort early if there is no mention at all of shield properties.
if (generatorProps == null)
return;

workingShields.Clear();
workingShields = new List<ThingStuffPair>();

//Initial filtering
if (generatorProps.shieldTags == null || generatorProps.shieldTags.Count == 0)
if (generatorProps.shieldTags == null || generatorProps.shieldTags?.Count == 0)
{
Log.Warning("PawnShields :: XML element shieldTags is null or empty for " + request.KindDef.defName);
return;
}
if (!pawn.RaceProps.ToolUser)

if (!(pawn?.RaceProps?.ToolUser ?? false))
{
Log.Warning("PawnShields :: " + request.KindDef.defName +
" is not a ToolUser or Humanlike in RaceProps.");
return;
}
if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
if (!(pawn.health?.capacities?.CapableOf(PawnCapacityDefOf.Manipulation) ?? false))
{
Log.Warning("PawnShields :: " + request.KindDef.defName + " is not capable of manipulation.");
return;
}
if (pawn.story != null && pawn.story.WorkTagIsDisabled(WorkTags.Violent))
{
if (pawn.story != null && ((bool) pawn.story?.WorkTagIsDisabled(WorkTags.Violent)))
return;
}

float randomInRange = generatorProps.shieldMoney.RandomInRange;
for (int i = 0; i < allShieldPairs.Count; i++)
{
ThingStuffPair w = allShieldPairs[i];
if (w.Price <= randomInRange)
var generatorPropsShieldMoney = generatorProps.shieldMoney;
float randomInRange = generatorPropsShieldMoney.RandomInRange;
if (allShieldPairs != null && allShieldPairs?.Count > 0)
foreach (var w in allShieldPairs)
{
if (generatorProps.shieldTags.Any(tag => w.thing.weaponTags.Contains(tag)))
{
if (w.thing.generateAllowChance >= 1f || Rand.ValueSeeded(pawn.thingIDNumber ^ 28554824) <= w.thing.generateAllowChance)
if (w.Price <= randomInRange)
if (!w.thing.weaponTags.NullOrEmpty())
{
workingShields.Add(w);
if (generatorProps.shieldTags.Any(tag =>
(w.thing.weaponTags.Contains(tag))))
{
if (w.thing.generateAllowChance >= 1f ||
Rand.ValueSeeded(pawn.thingIDNumber ^ 28554824) <= w.thing.generateAllowChance)
{
workingShields.Add(w);
}

}
}
}
}
}
if (workingShields.Count == 0)
if (workingShields == null || workingShields?.Count == 0)
{
Log.Warning("No working shields found for " + pawn.Label + "::" + pawn.KindLabel);
return;
}

ThingStuffPair thingStuffPair;
if (workingShields.TryRandomElementByWeight((ThingStuffPair w) => w.Commonality * w.Price, out thingStuffPair))
if (workingShields.TryRandomElementByWeight(w => w.Commonality * w.Price, out var thingStuffPair))
{
ThingWithComps thingWithComps = (ThingWithComps)ThingMaker.MakeThing(thingStuffPair.thing, thingStuffPair.stuff);
ThingWithComps thingWithComps =
(ThingWithComps) ThingMaker.MakeThing(thingStuffPair.thing, thingStuffPair.stuff);
PawnGenerator.PostProcessGeneratedGear(thingWithComps, pawn);
pawn.equipment.AddEquipment(thingWithComps);
pawn.equipment?.AddEquipment(thingWithComps);
//Log.Message(pawn.Label + " added shield " + thingWithComps.Label);
}
workingShields.Clear();
}

/// <summary>
/// Resets the shield generator.
/// </summary>
public static void Reset()
{
Predicate<ThingDef> isShield = (ThingDef td) => td.equipmentType != EquipmentType.Primary && td.canBeSpawningInventory && td.HasComp(typeof(CompShield));
allShieldPairs = ThingStuffPair.AllWith(isShield);
bool IsShield(ThingDef td) => td.equipmentType != EquipmentType.Primary && td.canBeSpawningInventory &&
td.HasComp(typeof(CompShield));

allShieldPairs = ThingStuffPair.AllWith(IsShield);

using (IEnumerator<ThingDef> enumerator = (from td in DefDatabase<ThingDef>.AllDefs
where isShield(td)
select td).GetEnumerator())
where IsShield(td)
select td).GetEnumerator())
{
while (enumerator.MoveNext())
{
ThingDef thingDef = enumerator.Current;
float num = (from pa in allShieldPairs
where pa.thing == thingDef
select pa).Sum((ThingStuffPair pa) => pa.Commonality);
where pa.thing == thingDef
select pa).Sum(pa => pa.Commonality);
if (thingDef == null) continue;
float num2 = thingDef.generateCommonality / num;
if (num2 != 1f)
if (num2 == 1f) continue;
for (int i = 0; i < allShieldPairs.Count; i++)
{
for (int i = 0; i < allShieldPairs.Count; i++)
ThingStuffPair thingStuffPair = allShieldPairs[i];
if (thingStuffPair.thing == thingDef)
{
ThingStuffPair thingStuffPair = allShieldPairs[i];
if (thingStuffPair.thing == thingDef)
{
allShieldPairs[i] = new ThingStuffPair(thingStuffPair.thing, thingStuffPair.stuff, thingStuffPair.commonalityMultiplier * num2);
}
allShieldPairs[i] = new ThingStuffPair(thingStuffPair.thing, thingStuffPair.stuff,
thingStuffPair.commonalityMultiplier * num2);
}
}
}
}
}
}
}
}
Binary file added Textures/quickstartIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6a814ce

Please sign in to comment.