1.5, added stuff, fixed stuff
- mod icon - fixes for new vanilla clipping issues - GenClosest optimization improving repairing, wardening, tending jobs - caching for new ListerBuildings methods - DynamicDrawManager single threading - Type.GetFields caching - StatParts analyzer category - removed duplicate steam warning and optionally window - added exception handling for debug menu, incidentworker, Graphic_Multi, InitializeComps, making all those now log what mod broke and not cause black screens or whatever
This commit is contained in:
@@ -3,227 +3,27 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
#if disabledForNow
|
||||
using System.Threading.Tasks;
|
||||
using Verse.AI;
|
||||
using PerformanceFish.Prepatching;
|
||||
|
||||
namespace PerformanceFish.JobSystem;
|
||||
|
||||
public sealed class GenClosestPatches : ClassWithFishPatches
|
||||
public sealed class GenClosestPatches : ClassWithFishPrepatches
|
||||
{
|
||||
public sealed class ClosestThing_Global_Patch : FishPatch
|
||||
public sealed class ClosestThingReachablePatch : FishPrepatch
|
||||
{
|
||||
public override string Description { get; } = "Threading for job scanning. Disabled and unstable.";
|
||||
public override bool DefaultState => false;
|
||||
public static bool ThreadingEnabled { get; set; }
|
||||
public override string Description { get; }
|
||||
= "Job scanning optimization making repairing, wardening and tending use a cache of targets where "
|
||||
+ "appropriate";
|
||||
|
||||
public override MethodBase TargetMethodBase => methodof(GenClosest.ClosestThingReachable);
|
||||
|
||||
public override Expression<Action> TargetMethod { get; }
|
||||
= static () => GenClosest.ClosestThing_Global(default, null, default, null, null);
|
||||
|
||||
public static CodeInstructions Transpiler(CodeInstructions CodeInstructions)
|
||||
=> Reflection.MakeReplacementCall(ClosestThing_Global_Replacement);
|
||||
|
||||
private struct Variables
|
||||
public static void Prefix(Map map, ref ThingRequest thingReq, IEnumerable<Thing>? customGlobalSearchSet)
|
||||
{
|
||||
public IntVec3 center;
|
||||
public float maxDistanceSquared;
|
||||
public Func<Thing, float>? priorityGetter;
|
||||
public float closestDistSquared;
|
||||
public Predicate<Thing>? validator;
|
||||
}
|
||||
if (!thingReq.CanBeFoundInRegion || customGlobalSearchSet is not ICollection<Thing> collection)
|
||||
return;
|
||||
|
||||
public static Thing? ClosestThing_Global_Replacement(IntVec3 center, IEnumerable? searchSet,
|
||||
float maxDistance = 99999f, Predicate<Thing>? validator = null, Func<Thing, float>? priorityGetter = null)
|
||||
{
|
||||
if (searchSet == null)
|
||||
return null;
|
||||
|
||||
var closestDistSquared = 2.14748365E+09f;
|
||||
Thing? chosen = null;
|
||||
var bestPrio = float.MinValue;
|
||||
//float maxDistanceSquared = maxDistance * maxDistance;
|
||||
Variables variables = new()
|
||||
{
|
||||
center = center,
|
||||
maxDistanceSquared = maxDistance * maxDistance,
|
||||
validator = validator,
|
||||
priorityGetter = priorityGetter,
|
||||
closestDistSquared = closestDistSquared
|
||||
};
|
||||
|
||||
var predicate = GenClosest_Predicate.GetValidator(validator?.Target)?.Target ?? validator?.Target;
|
||||
if (ThreadingEnabled
|
||||
&& validator != null
|
||||
&& JobGiver_Work_Predicate.GetScanner(predicate) is WorkGiver_DoBill
|
||||
/*or WorkGiver_ConstructDeliverResources or WorkGiver_ConstructFinishFrames*/
|
||||
)
|
||||
{
|
||||
if (searchSet is IList<Thing> thingList)
|
||||
{
|
||||
Log.Message($"Running threading code for {validator.Target.GetType()}");
|
||||
Exception? exception = null;
|
||||
try
|
||||
{
|
||||
Parallel.For<(IList<Thing> list, Variables vars)>(0, thingList.Count,
|
||||
() => (thingList, variables),
|
||||
(i, loop, listAndVars) => (listAndVars.list,
|
||||
ProcessThreaded(listAndVars.list[i], listAndVars.vars)), static _ => { });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
Log.Error($"Caught error while threading:\n{ex}");
|
||||
}
|
||||
|
||||
if (exception is null)
|
||||
Log.Message("Finished threading code without errors");
|
||||
|
||||
return chosen;
|
||||
}
|
||||
}
|
||||
|
||||
switch (searchSet)
|
||||
{
|
||||
case IList<Thing> thingList:
|
||||
{
|
||||
for (var i = 0; i < thingList.Count; i++)
|
||||
Process(thingList[i], variables);
|
||||
break;
|
||||
}
|
||||
case IList<Pawn> pawnList:
|
||||
{
|
||||
for (var j = 0; j < pawnList.Count; j++)
|
||||
Process(pawnList[j], variables);
|
||||
break;
|
||||
}
|
||||
case IList<Building> buildingList:
|
||||
{
|
||||
for (var k = 0; k < buildingList.Count; k++)
|
||||
Process(buildingList[k], variables);
|
||||
break;
|
||||
}
|
||||
case IList<IAttackTarget> attackTargetList:
|
||||
{
|
||||
for (var l = 0; l < attackTargetList.Count; l++)
|
||||
Process((Thing)attackTargetList[l], variables);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
foreach (Thing item in searchSet)
|
||||
Process(item, variables);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return chosen;
|
||||
|
||||
void Process<T>(T t, Variables variables) where T : Thing
|
||||
{
|
||||
if (!t.Spawned)
|
||||
return;
|
||||
|
||||
float num = (variables.center - t.Position).LengthHorizontalSquared;
|
||||
if (!(num > variables.maxDistanceSquared)
|
||||
&& (variables.priorityGetter != null || num < closestDistSquared)
|
||||
&& (variables.validator == null || variables.validator(t)))
|
||||
{
|
||||
var num2 = 0f;
|
||||
if (variables.priorityGetter != null)
|
||||
{
|
||||
num2 = variables.priorityGetter(t);
|
||||
if (num2 < bestPrio || (Math.Abs(num2 - bestPrio) < 0.001f && num >= closestDistSquared))
|
||||
return;
|
||||
}
|
||||
|
||||
chosen = t;
|
||||
closestDistSquared = variables.closestDistSquared = num;
|
||||
bestPrio = num2;
|
||||
}
|
||||
}
|
||||
|
||||
Variables ProcessThreaded<T>(T t, Variables variables) where T : Thing
|
||||
{
|
||||
if (!t.Spawned)
|
||||
return variables;
|
||||
|
||||
float num = (variables.center - t.Position).LengthHorizontalSquared;
|
||||
if (num > variables.maxDistanceSquared
|
||||
|| (variables.priorityGetter == null
|
||||
&& (!(num < variables.closestDistSquared)
|
||||
|| !(num < (variables.closestDistSquared = closestDistSquared))))
|
||||
|| (variables.validator != null && !variables.validator(t)))
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
var num2 = 0f;
|
||||
if (variables.priorityGetter != null)
|
||||
{
|
||||
num2 = variables.priorityGetter(t);
|
||||
if (num2 < bestPrio || (Math.Abs(num2 - bestPrio) < 0.001f && num >= closestDistSquared))
|
||||
return variables;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num >= closestDistSquared)
|
||||
return variables;
|
||||
}
|
||||
|
||||
chosen = t;
|
||||
closestDistSquared = variables.closestDistSquared = num;
|
||||
bestPrio = num2;
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
}
|
||||
|
||||
private static object Lock { get; } = new();
|
||||
|
||||
private static Type JobGiverWorkPredicateType { get; } = AccessTools.FirstInner(typeof(JobGiver_Work),
|
||||
t => AccessTools.Field(t, "scanner") != null
|
||||
&& AccessTools.FirstMethod(t, m => m.Name.Contains("TryIssueJobPackage")) != null);
|
||||
|
||||
private static JobGiver_Work_PredicateAccess JobGiver_Work_Predicate { get; }
|
||||
= (JobGiver_Work_PredicateAccess)Activator.CreateInstance(
|
||||
typeof(JobGiver_Work_PredicateAccessImplementation<>).MakeGenericType(JobGiverWorkPredicateType));
|
||||
|
||||
private static Type GenClosestPredicateType { get; } = AccessTools.FirstInner(typeof(GenClosest),
|
||||
t => AccessTools.Field(t, "validator") != null
|
||||
&& AccessTools.FirstMethod(t, m => m.Name.Contains("ClosestThingReachable")) != null);
|
||||
|
||||
private static GenClosest_PredicateAccess GenClosest_Predicate { get; }
|
||||
= (GenClosest_PredicateAccess)Activator.CreateInstance(
|
||||
typeof(GenClosest_PredicateAccessImplementation<>).MakeGenericType(GenClosestPredicateType));
|
||||
|
||||
private abstract class JobGiver_Work_PredicateAccess
|
||||
{
|
||||
public abstract WorkGiver_Scanner? GetScanner(object? obj);
|
||||
}
|
||||
|
||||
private class JobGiver_Work_PredicateAccessImplementation<T> : JobGiver_Work_PredicateAccess
|
||||
{
|
||||
public override WorkGiver_Scanner? GetScanner(object? obj) => obj is T t ? Scanner(t) : null;
|
||||
|
||||
public static AccessTools.FieldRef<T, WorkGiver_Scanner> Scanner { get; }
|
||||
= AccessTools.FieldRefAccess<T, WorkGiver_Scanner>("scanner");
|
||||
}
|
||||
|
||||
private abstract class GenClosest_PredicateAccess
|
||||
{
|
||||
public abstract Predicate<Thing>? GetValidator(object? obj);
|
||||
}
|
||||
|
||||
private class GenClosest_PredicateAccessImplementation<T> : GenClosest_PredicateAccess
|
||||
{
|
||||
public override Predicate<Thing>? GetValidator(object? obj) => obj is T t ? Validator(t) : null;
|
||||
|
||||
public static AccessTools.FieldRef<T, Predicate<Thing>> Validator { get; }
|
||||
= AccessTools.FieldRefAccess<T, Predicate<Thing>>("validator");
|
||||
if (map.listerThings.ThingsMatching(thingReq).Count > collection.Count * 5)
|
||||
thingReq = ThingRequest.ForUndefined();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//}
|
||||
}
|
||||
Reference in New Issue
Block a user