Skip to content

Commit

Permalink
Updated for rimworld beta 18
Browse files Browse the repository at this point in the history
  • Loading branch information
jkluch committed Nov 27, 2017
1 parent ed6c2d3 commit e55b24e
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 41 deletions.
4 changes: 3 additions & 1 deletion HaulToStack.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
Expand Down Expand Up @@ -112,6 +113,7 @@
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Source\HaulToStack.cs" />
<Compile Include="Source\HaulUtils.cs" />
<Compile Include="Source\JobDriver_HaulToStack.cs" />
<Compile Include="Source\PlannedHauls.cs" />
</ItemGroup>
Expand Down
18 changes: 12 additions & 6 deletions Mods/HaulToStack/About/About.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@
<ModMetaData>
<name>Haul to Stack</name>
<author>ItsComcastic</author>
<targetVersion>0.17.0</targetVersion>
<targetVersion>0.18.0</targetVersion>
<url></url>
<description>
Version 0.17
Version .18

Instead of hauling to random tiles your pawn *should* always haul to a stack if it has room on it

Features
Haulers will check for an existing stack to add it's item to. Haulers no longer reserve the haul-to tile meaning multiple pawns can haul to the same tile at once.
Haulers will check for an existing stack to add it's item to.
Haulers no longer reserve the haul-to tile meaning multiple pawns can haul to the same tile at once.


Issues
You may still see your pawns haul to different stacks, this will happen if there are no stacks, or full stacks in the stockpile and two or more pawns try to haul new items at once or if an animal is hauling. Example: If you get a pod drop with new loot and two pawns pickup some before any is placed, they might pick different spots in the stockpile to haul to. I'm working on a system where they can share with eachother which tile they plan on placing new loot on which should fix that issue and prevent the need for Stack Merger by Fluffy
You may still see your pawns haul to different stacks, this will happen under the following conditions:
there are no existing stacks,
the existing stacks are full

Example: If you get a pod drop with new loot and two pawns pickup some before any is placed, they might pick different spots in the stockpile to haul to. I'm working on a system where they can share with eachother which tile they plan on placing new loot on which should fix that issue and prevent the need for Stack Merger by Fluffy

Conflicts
It looks like there might be a conflict with a wall light mod if your stash runs against the wall light. If you have wall lights against your stash take that tile out of your stockpile zone to prevent pawns from going into a loop of trying to haul over and over. This issue isn't fixable by changing mod order unfortunately, I'll have to work with the mod creater on a solution.
Expand All @@ -24,9 +30,9 @@ If you want to remove or turn off this mod you need to first make sure no one is
You can force this by pausing, drafting any pawns where their state says they're 'Hauling", save.. turn off the mod, then load that save and undraft the pawns. If you don't do this the pawn and what they were holding will 'disappear' and the game will throw errors. If you reload your 'broken' save with the mod they should reappear.

Recommendations
Install Stack Merger by Fluffy in addition to this mod. On rare occasions pawns could haul items that don't have an existing stock pile to different tiles because both pawns look for a location to place the item at the same time and if nothing exists they may pick different tiles for placing. Fluffy's mod will handle those cases.
Install Stack Merger by Fluffy in addition to this mod.

Thanks to @Trips for the Haul to Stack preview picture.
Thanks to @Trips on the rimworld discord server for the Haul to Stack preview picture.

Github
https://github.com/jkluch/HaulToStack
Expand Down
Binary file modified Mods/HaulToStack/Assemblies/$HugsLibChecker.dll
Binary file not shown.
Binary file modified Mods/HaulToStack/Assemblies/HaulToStack.dll
Binary file not shown.
13 changes: 8 additions & 5 deletions Source/HaulToStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,12 @@ static bool TryFindBestBetterStoreCellForReplacement(Thing t, Pawn carrier, Map

if (!(num3 <= num))
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("Game usually doesn't attempt to haul on this condition");
#endif
if (CellIsReachable(intVec2, map, t, carrier, faction))
{
String stackSituation = CellCanStack(intVec2, map, t);
string stackSituation = CellCanStack(intVec2, map, t);
if (stackSituation.Equals("stackable"))
{
//This is the ideal situation
Expand All @@ -122,7 +125,7 @@ static bool TryFindBestBetterStoreCellForReplacement(Thing t, Pawn carrier, Map
{
if (CellIsReachable(intVec2, map, t, carrier, faction))
{
String stackSituation = CellCanStack(intVec2, map, t);
string stackSituation = CellCanStack(intVec2, map, t);

if (stackSituation.Equals("clear"))
{
Expand Down Expand Up @@ -205,20 +208,20 @@ static bool CellIsReachable(IntVec3 c, Map map, Thing t, Pawn carrier, Faction f
*/
if (carrier != null)
{
if (!carrier.CanReserve(c, 1, -1, null, false))
if (!carrier.CanReserveNew(c))
{
return false;
}
}
else if (map.reservationManager.IsReserved(c, faction))
else if (faction != null && map.reservationManager.IsReservedByAnyoneOf(c, faction))
{
return false;
}
return !c.ContainsStaticFire(map) && (carrier == null || carrier.Map.reachability.CanReach((!t.SpawnedOrAnyParentSpawned) ? carrier.PositionHeld : t.PositionHeld, c, PathEndMode.ClosestTouch, TraverseParms.For(carrier, Danger.Deadly, TraverseMode.ByPawn, false)));
}


static String CellCanStack(IntVec3 c, Map map, Thing thing)
static string CellCanStack(IntVec3 c, Map map, Thing thing)
{
List<Thing> list = map.thingGrid.ThingsListAt(c);
bool potentialStack = false;
Expand Down
165 changes: 165 additions & 0 deletions Source/HaulUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;

using Harmony;
using HugsLib;
using HugsLib.Utils;
using RimWorld;
using Verse;
using UnityEngine;
using System.Reflection;
using Verse.AI;

namespace HaulToStack
{
class HaulUtils
{
public static String CellCanStack(IntVec3 location, Map map, Thing thing)
{
List<Thing> list = map.thingGrid.ThingsListAt(location);
bool potentialStack = false;
for (int i = 0; i < list.Count; i++)
{
Thing thing2 = list[i];

//HaulToStack.Instance.Logger.Trace("Item on tile is: " + thing2.def.defName);
//HaulToStack.Instance.Logger.Trace("Item on hand is: " + thing.def.defName);

if (thing2.def.EverStoreable)
{
if (!thing2.CanStackWith(thing))
{
//HaulToStack.Instance.Logger.Trace("Can't stack on eachother");
return "unusable";
}
if (thing2.stackCount >= thing.def.stackLimit)
{
//HaulToStack.Instance.Logger.Trace("Stack count issue");
return "unusable";
}
}
if (thing2.def.entityDefToBuild != null && thing2.def.entityDefToBuild.passability != Traversability.Standable)
{
//HaulToStack.Instance.Logger.Trace("impassible terrain");
return "unusable";
}
if (thing2.def.surfaceType == SurfaceType.None && thing2.def.passability != Traversability.Standable)
{
//HaulToStack.Instance.Logger.Trace("different impassible terrain");
return "unusable";
}
if (thing2.def.defName.Equals(thing.def.defName))
{
potentialStack = true;
}
}
if (potentialStack)
{
return "stackable";
}
return "clear";
}

internal static bool ShouldReserveHaulLocation(Thing thing, IntVec3 destination, Pawn pawn, Map map)
{
var destinationThing = map.thingGrid.ThingsListAt(destination).Find(x => x.def.defName == thing.def.defName);

#if DEBUG
HaulToStack.Instance.Logger.Trace("Checking if we should reserve the destination");
HaulToStack.Instance.Logger.Trace("Pawn grabbing stack of: " + thing.stackCount);
#endif
//If this is the case, we are carrying to a new (clear) location
//Technically we also would want to reserve if the max stack size of the item is one
//However we already are handling that case in TryMakePreToilReservations()
if (destinationThing == null)
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("NOT RESERVING DESTINATION");
HaulToStack.Instance.Logger.Trace("Destination empty, not reserving");
#endif
return false;
}


//If pawn currently isn't holding anything just check the destination stack + hauling stack
if (pawn.carryTracker.CarriedThing == null)
{
if (destinationThing.stackCount + Math.Min(pawn.carryTracker.MaxStackSpaceEver(thing.def), thing.stackCount) >= thing.def.stackLimit)
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("RESERVING DESTINATION");
HaulToStack.Instance.Logger.Trace("Pawn not carrying anything but the stack they're grabbing is going to overfill the destination");
#endif
return true;
}
else
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("NOT RESERVING DESTINATION");
HaulToStack.Instance.Logger.Trace("Pawn can't carry enough to fill the destination stack");
#endif
return false;
}
}

//Destination has a stack
//Pawn is holding items
#if DEBUG
HaulToStack.Instance.Logger.Trace("Pawn holding stack of: " + pawn.carryTracker.CarriedThing.stackCount);
#endif

if (destinationThing.stackCount + pawn.carryTracker.CarriedThing.stackCount + thing.stackCount >= thing.def.stackLimit)
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("RESERVING DESTINATION");
HaulToStack.Instance.Logger.Trace("Pawn is going to overfill the destination");
#endif
return true;
}
else
{
#if DEBUG
HaulToStack.Instance.Logger.Trace("NOT RESERVING DESTINATION");
HaulToStack.Instance.Logger.Trace("Pawn isn't carrying enough to fill the destination stack");
#endif
return false;
}

}

internal static Toil CheckForGetOpportunityDuplicateReplace(Toil getHaulTargetToil, TargetIndex haulableInd, TargetIndex storeCellInd, bool takeFromValidStorage = false, Predicate<Thing> extraValidator = null)
{
Toil toil = new Toil();
toil.initAction = delegate
{
Pawn actor = toil.actor;
Job curJob = actor.jobs.curJob;
if (actor.carryTracker.CarriedThing.def.stackLimit == 1)
{
return;
}
if (actor.carryTracker.Full)
{
return;
}
if (curJob.count <= 0)
{
return;
}
Predicate<Thing> validator = (Thing t) => t.Spawned && t.def == actor.carryTracker.CarriedThing.def && t.CanStackWith(actor.carryTracker.CarriedThing) && !t.IsForbidden(actor) && (takeFromValidStorage || !t.IsInValidStorage()) && (storeCellInd == TargetIndex.None || curJob.GetTarget(storeCellInd).Cell.IsValidStorageFor(actor.Map, t)) && actor.CanReserve(t, 1, -1, null, false) && (extraValidator == null || extraValidator(t));
Thing thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableAlways), PathEndMode.ClosestTouch, TraverseParms.For(actor, Danger.Deadly, TraverseMode.ByPawn, false), 8f, validator, null, 0, -1, false, RegionType.Set_Passable, false);
if (thing != null)
{
curJob.SetTarget(haulableInd, thing);
actor.jobs.curDriver.JumpToToil(getHaulTargetToil);
#if DEBUG
HaulToStack.Instance.Logger.Trace("In opportunistic pickup");
#endif
if ( ShouldReserveHaulLocation(curJob.targetA.Thing, curJob.targetB.Cell, actor, actor.Map) )
actor.Reserve(curJob.GetTarget(storeCellInd), curJob);
}
};
return toil;
}
}
}
Loading

0 comments on commit e55b24e

Please sign in to comment.