Skip to content

Commit

Permalink
Merge pull request #2905 from CombatExtended-Continued/cacheheights
Browse files Browse the repository at this point in the history
Cache pawn heights
  • Loading branch information
N7Huntsman authored Dec 2, 2023
2 parents 1d1fe4c + a09af0c commit a6d1b83
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 54 deletions.
22 changes: 21 additions & 1 deletion Source/CombatExtended/CombatExtended/CE_Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -930,13 +930,30 @@ public static Bounds GetBoundsFor(IntVec3 cell, RoofDef roof)
new Vector3(1f, height, 1f));
}

public static CollisionVertical GetCollisionVertical(this Thing thing)
{
if (thing is Pawn pawn)
{
return pawn.GetTacticalManager().Collision;
}
return new CollisionVertical(thing);
}

public static Bounds GetBoundsFor(Thing thing)
{
if (thing == null)
{
return new Bounds();
}
var height = new CollisionVertical(thing);
CollisionVertical height;
if (thing is Pawn pawn)
{
height = pawn.GetTacticalManager().Collision;
}
else
{
height = new CollisionVertical(thing);
}
float length;
float width;
var thingPos = thing.DrawPos;
Expand Down Expand Up @@ -1504,5 +1521,8 @@ public static Pawn GetRandomWorldPawn(this Faction faction, bool capableOfCombat
}

public static FactionStrengthTracker GetStrengthTracker(this Faction faction) => Find.World.GetComponent<WorldStrengthTracker>().GetFactionTracker(faction);

public static CompTacticalManager GetTacticalManager(this Pawn pawn) => pawn.TryGetComp<CompTacticalManager>();

}
}
111 changes: 63 additions & 48 deletions Source/CombatExtended/CombatExtended/CollisionVertical.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,35 @@ public struct CollisionVertical
public const float BodyRegionBottomHeight = 0.45f; // Hits below this percentage will impact the corresponding body region
public const float BodyRegionMiddleHeight = 0.85f; // This also sets the altitude at which pawns hold their guns

private readonly FloatRange heightRange;
public readonly float shotHeight;
private FloatRange heightRange;
public float shotHeight;

public FloatRange HeightRange => new FloatRange(heightRange.min, heightRange.max);
public FloatRange HeightRange => heightRange;
public float Min => heightRange.min;
public float Max => heightRange.max;
public float BottomHeight => Max * BodyRegionBottomHeight;
public float MiddleHeight => Max * BodyRegionMiddleHeight;

public CollisionVertical(Thing thing)
{
CalculateHeightRange(thing, out heightRange, out shotHeight);
heightRange = new FloatRange(0, 0);
shotHeight = 0f;
CalculateHeightRange(thing);
}

private static void CalculateHeightRange(Thing thing, out FloatRange heightRange, out float shotHeight)
private void CalculateHeightRange(Thing thing)
{
shotHeight = 0;
heightRange = new FloatRange(0, 0);
heightRange.min = heightRange.max = 0f;
if (thing == null)
{
return;
}

var plant = thing as Plant;
if (plant != null)
if (thing is Plant plant)
{
//Height matches up exactly with visual size
heightRange = new FloatRange(0f, BoundsInjector.ForPlant(plant).y);
heightRange.max = BoundsInjector.ForPlant(plant).y;
return;
}

Expand All @@ -58,68 +59,82 @@ private static void CalculateHeightRange(Thing thing, out FloatRange heightRange

if (thing.def.Fillage == FillCategory.Full)
{
heightRange = new FloatRange(0, WallCollisionHeight);
heightRange.max = WallCollisionHeight;
shotHeight = WallCollisionHeight;
return;
}
float fillPercent = thing.def.fillPercent;
heightRange = new FloatRange(Mathf.Min(0f, fillPercent), Mathf.Max(0f, fillPercent));
heightRange.min = Mathf.Min(0f, fillPercent);
heightRange.max = Mathf.Max(0f, fillPercent);
shotHeight = fillPercent;
return;
}

float collisionHeight = 0f;
float shotHeightOffset = 0;
float heightAdjust = CETrenches.GetHeightAdjust(thing.Position, thing.Map);

var pawn = thing as Pawn;
if (pawn != null)
if (thing is Pawn pawn)
{
collisionHeight = CE_Utility.GetCollisionBodyFactors(pawn).y;
RecalculateHeight(pawn, heightAdjust);
return;
}
float collisionHeight = thing.def.fillPercent;
float fillPercent2 = collisionHeight;
heightRange.min = Mathf.Min(0, collisionHeight) + heightAdjust;
heightRange.max = Mathf.Max(0, collisionHeight) + heightAdjust;
shotHeight = heightRange.max;
}

shotHeightOffset = collisionHeight * (1 - BodyRegionMiddleHeight);
public void RecalculateHeight(Pawn pawn, float heightAdjust)
{
float collisionHeight = CE_Utility.GetCollisionBodyFactors(pawn).y;
heightRange.min = heightAdjust;
heightRange.max = heightAdjust + collisionHeight;
float shotHeightOffset = shotHeight = collisionHeight * (1 - BodyRegionMiddleHeight);

if (pawn.Downed)
{
collisionHeight = BodyRegionBottomHeight * BodyRegionBottomHeight * collisionHeight;
heightRange.max = heightAdjust + collisionHeight;
shotHeight = collisionHeight * (1 - BodyRegionMiddleHeight);
return;
}

// Humanlikes in combat crouch to reduce their profile
if (pawn.IsCrouching())
// Humanlikes in combat crouch to reduce their profile
if (pawn.IsCrouching())
{
float crouchHeight = BodyRegionBottomHeight * collisionHeight; // Minimum height we can crouch down to
// check our stance if we are shooting over cover.
Stance curStance = pawn.stances.curStance;
LocalTargetInfo currentTarget = null;
if (curStance is Stance_Warmup || curStance is Stance_Cooldown)
{
float crouchHeight = BodyRegionBottomHeight * collisionHeight; // Minimum height we can crouch down to
currentTarget = ((Stance_Busy)curStance).focusTarg;
}

// Find the highest adjacent cover
Map map = pawn.Map;

// Find the highest adjacent cover
Map map = pawn.Map;
foreach (IntVec3 curCell in GenAdjFast.AdjacentCells8Way(pawn.Position))
if (currentTarget != null && currentTarget.IsValid)
{
foreach (IntVec3 curCell in GenSight.PointsOnLineOfSight(pawn.Position, currentTarget.Cell))
{
if (curCell.InBounds(map))
Thing cover = curCell.GetCover(map);
if (cover != null && cover.def.Fillage == FillCategory.Partial && !cover.IsPlant())
{
Thing cover = curCell.GetCover(map);
if (cover != null && cover.def.Fillage == FillCategory.Partial && !cover.IsPlant())
var coverHeight = new CollisionVertical(cover).Max;
if (coverHeight > crouchHeight)
{
var coverHeight = new CollisionVertical(cover).Max - heightAdjust;
if (coverHeight > crouchHeight)
{
crouchHeight = coverHeight;
}
crouchHeight = coverHeight;
}
}
break;
}
collisionHeight = Mathf.Min(collisionHeight, crouchHeight + 0.01f + shotHeightOffset); // We crouch down only so far that we can still shoot over our own cover and never beyond our own body size
}
collisionHeight = Mathf.Min(collisionHeight, crouchHeight + 0.01f + shotHeightOffset); // We crouch down only so far that we can still shoot over our own cover and never beyond our own body size
heightRange.min = heightAdjust;
heightRange.max = heightAdjust + collisionHeight;
shotHeight = shotHeightOffset;
}
else
{
collisionHeight = thing.def.fillPercent;
}
var edificeHeight = 0f;
if (thing.Map != null)
{
var edifice = thing.Position.GetCover(thing.Map);
if (edifice != null && edifice.GetHashCode() != thing.GetHashCode() && !edifice.IsPlant())
{
edificeHeight = new CollisionVertical(edifice).heightRange.max;
}
}
float fillPercent2 = collisionHeight;
heightRange = new FloatRange(Mathf.Min(edificeHeight, edificeHeight + fillPercent2) + heightAdjust, Mathf.Max(edificeHeight, edificeHeight + fillPercent2) + heightAdjust);
shotHeight = heightRange.max - shotHeightOffset;
}

/// <summary>
Expand Down
18 changes: 18 additions & 0 deletions Source/CombatExtended/CombatExtended/Comps/CompTacticalManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,26 @@
using RimWorld;
using Verse;
using Verse.AI;
using CombatExtended.Compatibility;

namespace CombatExtended
{
public class CompTacticalManager : ThingComp
{
public CollisionVertical? collision = null;

public CollisionVertical Collision
{
get
{
if (collision == null)
{
collision = new CollisionVertical(SelPawn);
}
return (CollisionVertical)collision;
}
}

private Job curJob = null;
private List<Verse.WeakReference<Pawn>> targetedBy = new List<Verse.WeakReference<Pawn>>();

Expand Down Expand Up @@ -141,6 +156,9 @@ public bool DraftedColonist
public override void CompTick()
{
base.CompTick();
float heightAdjust = CETrenches.GetHeightAdjust(SelPawn.Position, SelPawn.Map);
this.Collision.RecalculateHeight(SelPawn, heightAdjust);

if (parent.IsHashIntervalTick(120))
{
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ protected float ShotSpeed
return shotSpeed;
}
}
public float ShotHeight => (new CollisionVertical(caster)).shotHeight;
public float ShotHeight => caster.GetCollisionVertical().shotHeight;
private Vector3 ShotSource
{
get
Expand Down Expand Up @@ -391,7 +391,7 @@ public virtual void ShiftTarget(ShiftVecReport report, bool calculateMechanicalO
// Height difference calculations for ShotAngle
float targetHeight = 0f;

var coverRange = new CollisionVertical(report.cover).HeightRange; //Get " " cover, assume it is the edifice
var coverRange = report.cover.GetCollisionVertical().HeightRange; //Get " " cover, assume it is the edifice

// Projectiles with flyOverhead target the surface in front of the target
if (Projectile.projectile.flyOverhead)
Expand All @@ -400,7 +400,7 @@ public virtual void ShiftTarget(ShiftVecReport report, bool calculateMechanicalO
}
else
{
var victimVert = new CollisionVertical(currentTarget.Thing);
var victimVert = currentTarget.Thing.GetCollisionVertical();
var targetRange = victimVert.HeightRange; //Get lower and upper heights of the target
if (targetRange.min < coverRange.max) //Some part of the target is hidden behind some cover
{
Expand Down Expand Up @@ -782,7 +782,7 @@ private bool GetHighestCoverAndSmokeForTarget(LocalTargetInfo target, out Thing
&& newCover.def.Fillage == FillCategory.Partial
&& !newCover.IsPlant())
{
float newCoverHeight = new CollisionVertical(newCover).Max;
float newCoverHeight = newCover.GetCollisionVertical().Max;

if (highestCover == null || highestCoverHeight < newCoverHeight)
{
Expand Down Expand Up @@ -1280,7 +1280,7 @@ private bool CanHitCellFromCellIgnoringRange(Vector3 shotSource, IntVec3 targetL
AdjustShotHeight(caster, targetThing, ref shotHeight);
shotSource.y = shotHeight;
Vector3 targDrawPos = targetThing.DrawPos;
targetPos = new Vector3(targDrawPos.x, new CollisionVertical(targetThing).Max, targDrawPos.z);
targetPos = new Vector3(targDrawPos.x, targetThing.GetCollisionVertical().Max, targDrawPos.z);
var targPawn = targetThing as Pawn;
if (targPawn != null)
{
Expand Down

0 comments on commit a6d1b83

Please sign in to comment.