diff --git a/1.4/Assemblies/SmashTools.dll b/1.4/Assemblies/SmashTools.dll
index afa4324d..2bc47fe0 100644
Binary files a/1.4/Assemblies/SmashTools.dll and b/1.4/Assemblies/SmashTools.dll differ
diff --git a/1.4/Assemblies/UpdateLogTool.dll b/1.4/Assemblies/UpdateLogTool.dll
index e9780af7..9ce6db41 100644
Binary files a/1.4/Assemblies/UpdateLogTool.dll and b/1.4/Assemblies/UpdateLogTool.dll differ
diff --git a/1.4/Assemblies/Vehicles.dll b/1.4/Assemblies/Vehicles.dll
index 4b77529c..228cead8 100644
Binary files a/1.4/Assemblies/Vehicles.dll and b/1.4/Assemblies/Vehicles.dll differ
diff --git a/1.5/Assemblies/0Harmony.dll b/1.5/Assemblies/0Harmony.dll
index 86fc5eb5..7aac19c3 100644
Binary files a/1.5/Assemblies/0Harmony.dll and b/1.5/Assemblies/0Harmony.dll differ
diff --git a/1.5/Assemblies/SmashTools.dll b/1.5/Assemblies/SmashTools.dll
index 798ce306..8f5ac78e 100644
Binary files a/1.5/Assemblies/SmashTools.dll and b/1.5/Assemblies/SmashTools.dll differ
diff --git a/1.5/Assemblies/UpdateLogTool.dll b/1.5/Assemblies/UpdateLogTool.dll
index 1667ee4d..ec08d0fc 100644
Binary files a/1.5/Assemblies/UpdateLogTool.dll and b/1.5/Assemblies/UpdateLogTool.dll differ
diff --git a/1.5/Assemblies/Vehicles.dll b/1.5/Assemblies/Vehicles.dll
index f564beee..9be1e9d3 100644
Binary files a/1.5/Assemblies/Vehicles.dll and b/1.5/Assemblies/Vehicles.dll differ
diff --git a/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Comps.xml b/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Comps.xml
index af60a8da..4cfe36d5 100644
--- a/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Comps.xml
+++ b/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Comps.xml
@@ -9,4 +9,13 @@
Refueled
+
+
+
+ Deployed
+
+
+
+ Undeployed
+
diff --git a/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Upgrade.xml b/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Upgrade.xml
new file mode 100644
index 00000000..4b0d187a
--- /dev/null
+++ b/1.5/Defs/VehiclesDefs/Events/VehicleEventDef_Upgrade.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ VehicleUpgradeEnqueued
+
+
+
+ VehicleUpgradeCompleted
+
+
+
+ VehicleUpgradeRefundEnqueued
+
+
+
+ VehicleUpgradeRefundCompleted
+
+
diff --git a/1.5/Defs/VehiclesDefs/StatDefs/StatUpgradeCategoryDefs.xml b/1.5/Defs/VehiclesDefs/StatDefs/StatUpgradeCategoryDefs.xml
index e93c88b0..27115331 100644
--- a/1.5/Defs/VehiclesDefs/StatDefs/StatUpgradeCategoryDefs.xml
+++ b/1.5/Defs/VehiclesDefs/StatDefs/StatUpgradeCategoryDefs.xml
@@ -1,35 +1,80 @@
+
+
FuelCapacity
+
+
+ Integer
+ Positive
- FuelEfficiency
+ FuelConsumptionRate
+
+
+ FloatOne
+ {0}/day
+ Negative
- FuelConsumptionRate
+ ChargeRate
+
+
+ {0} /day
+ Positive
+
+ DischargeRate
+
+
+ {0} /day
+ Negative
+
+
+
WorldSpeedMultiplier
+
+
+ PercentZero
+ Positive
- OffRoadEfficiency
+ OffRoadMultiplier
+
+
+ PercentZero
+ Negative
- WinterPathCost
+ WinterCostMultiplier
+
+
+ FloatOne
+ Negative
+
PawnCollisionMultiplier
+
+
+ PercentZero
+ Positive
PawnCollisionRecoilMultiplier
+
+
+ PercentZero
+ Negative
\ No newline at end of file
diff --git a/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_Aerial.xml b/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_Aerial.xml
index 3ff28259..de5b56c3 100644
--- a/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_Aerial.xml
+++ b/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_Aerial.xml
@@ -13,6 +13,7 @@
{0} t/s
Average
100
+ Positive
FloatBox
diff --git a/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_General.xml b/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_General.xml
index c915d558..8ec7ff2c 100644
--- a/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_General.xml
+++ b/1.5/Defs/VehiclesDefs/StatDefs/VehicleStatDefs_General.xml
@@ -14,7 +14,8 @@
{0} c/s
Average
100
-
+ Positive
+
SliderFloat
2
@@ -50,7 +51,8 @@
{0} kg
Average
90
-
+ Positive
+
IntegerBox
@@ -68,7 +70,8 @@
{0} hp/s
Average
80
-
+ Positive
+
SliderFloat
1
@@ -88,7 +91,8 @@
{0} kg
None
50
-
+ None
+
IntegerBox
0
diff --git a/About/About.xml b/About/About.xml
index 5692e206..af22e7a8 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -2,7 +2,7 @@
Vehicle Framework
Smash Phil
SmashPhil.VehicleFramework
- 1.5.1586
+ 1.5.1659
1.4
1.5
diff --git a/BuildDate.txt b/BuildDate.txt
new file mode 100644
index 00000000..35544a48
--- /dev/null
+++ b/BuildDate.txt
@@ -0,0 +1 @@
+Mon 12/11/2023 03:20:41
\ No newline at end of file
diff --git a/Languages/English/Keyed/Labels.xml b/Languages/English/Keyed/Labels.xml
index b0fdc882..3bfdbf8a 100644
--- a/Languages/English/Keyed/Labels.xml
+++ b/Languages/English/Keyed/Labels.xml
@@ -11,13 +11,15 @@
Unload All Pawns
Unload {0}
Unable to exit vehicle. No valid cells to exit onto.
-
+ {0} is being upgraded.
+
Stop
Turn Off
Drafts vehicle allowing it to move. This will consume fuel if applicable even if the vehicle is idle.
Stop the vehicle immediately.
Undrafts vehicle, disabling the consumption of fuel and disallowing movement.
Refuel From Inventory
+ Fuel: {0}
Show All Items On Map
@@ -99,7 +101,11 @@
Health
Efficiency
Armor
-
+ Depth
+ Internal
+ External
+ Undefined
+
No Return Trip
Out Of Range
Cancel landing in this map? Aerial vehicle will be kicked out to the world map.
diff --git a/Languages/English/Keyed/Settings.xml b/Languages/English/Keyed/Settings.xml
index 0a56ea03..a263086d 100644
--- a/Languages/English/Keyed/Settings.xml
+++ b/Languages/English/Keyed/Settings.xml
@@ -105,7 +105,7 @@ Determines whether Vehicles should use values from the mod settings or DefsStats
- Upgrades (Disabled)
+ Upgrades
Draw Upgrade Menu Info Screen
Draw additional menu on the upgrade menu to display ship stats and ship icon.
Override Draw Color
diff --git a/Languages/English/Keyed/Settings_Debug.xml b/Languages/English/Keyed/Settings_Debug.xml
index 6c42450b..956db04c 100644
--- a/Languages/English/Keyed/Settings_Debug.xml
+++ b/Languages/English/Keyed/Settings_Debug.xml
@@ -23,7 +23,9 @@
Enable message logging to output specific values and pieces of information useful for debugging Vehicles. Use only if you're making a Vehicle add-on.
Debug PathCost Recalculation Logging
Log summary of path cost change for all vehicles affected by region dirtying.
-
+ Log Thread Activity
+ Log ongoing async actions on the dedicated thread of the current map in view.
+
Draft Any Vehicle
Be able to draft and move any vehicle regardless of passengers. Useful for empty boats in deep water or if you want to expedite testing.
diff --git a/Languages/English/Keyed/Settings_Fields.xml b/Languages/English/Keyed/Settings_Fields.xml
index 1027c627..036e469b 100644
--- a/Languages/English/Keyed/Settings_Fields.xml
+++ b/Languages/English/Keyed/Settings_Fields.xml
@@ -49,8 +49,10 @@
Vehicle Jobs
Max Workers
+ Off Road Multiplier
+ PathCost multiplier for traveling on roads.
Winter Speed Multiplier
- Additional cost for traveling during winter.
+ PathCost multiplier for traveling during winter.
World Speed Multiplier
Multiplier to MoveSpeed when on the world map in a caravan.
diff --git a/Languages/English/Keyed/SmashTools.xml b/Languages/English/Keyed/SmashTools.xml
new file mode 100644
index 00000000..49547c5e
--- /dev/null
+++ b/Languages/English/Keyed/SmashTools.xml
@@ -0,0 +1,22 @@
+
+
+
+ Animation
+ Create New Clip...
+
+ Preview
+ Enable/disable preview mode of entity's animation in-game
+ Play the animation
+ Pause the animation
+ Go to the beginning of the animation
+ Go to previous keyframe
+ Go to next keyframe
+ Go to the end of the animation
+
+ Add keyframe
+ Add event
+ Add Property
+
+ Dopesheet
+ Curves
+
diff --git a/Languages/English/Keyed/Status.xml b/Languages/English/Keyed/Status.xml
index 70b8f4ab..160928e8 100644
--- a/Languages/English/Keyed/Status.xml
+++ b/Languages/English/Keyed/Status.xml
@@ -15,4 +15,8 @@
Inoperable
Ruined
Beached
+
+ Generating Vehicle PathData
+ Generating PathGrids
+ Generating Vehicle Regions
\ No newline at end of file
diff --git a/Source/Vehicles/AI/Incidents/IncidentWorker_ShuttleDowned.cs b/Source/Vehicles/AI/Incidents/IncidentWorker_ShuttleDowned.cs
index 6063e148..674a9bcb 100644
--- a/Source/Vehicles/AI/Incidents/IncidentWorker_ShuttleDowned.cs
+++ b/Source/Vehicles/AI/Incidents/IncidentWorker_ShuttleDowned.cs
@@ -6,6 +6,7 @@
using RimWorld;
using RimWorld.Planet;
using SmashTools;
+using Verse.Noise;
namespace Vehicles
{
@@ -95,6 +96,7 @@ protected virtual int GenerateMapAndReinforcements(AerialVehicleInFlight aerialV
{
ticksTillArrival = (crashSite.Parent as CrashSite).InitiateReinforcementsRequest(settlement);
}
+ GetOrGenerateMapUtility.UnfogMapFromEdge(crashSite);
}
return ticksTillArrival;
}
diff --git a/Source/Vehicles/AI/JobDrivers/JobDriver_LoadVehicle.cs b/Source/Vehicles/AI/JobDrivers/JobDriver_LoadVehicle.cs
index 3fe0aa9f..75cc6d7a 100644
--- a/Source/Vehicles/AI/JobDrivers/JobDriver_LoadVehicle.cs
+++ b/Source/Vehicles/AI/JobDrivers/JobDriver_LoadVehicle.cs
@@ -34,8 +34,7 @@ public virtual VehiclePawn Vehicle
public virtual bool FailJob()
{
- bool listed = !Map.GetCachedMapComponent().VehicleListed(Vehicle, ListerTag);
- return listed;
+ return !MapComponentCache.GetComponent(Map).VehicleListed(Vehicle, ListerTag);
}
public override bool TryMakePreToilReservations(bool errorOnFailed)
diff --git a/Source/Vehicles/AI/JobDrivers/JobDriver_RepairVehicle.cs b/Source/Vehicles/AI/JobDrivers/JobDriver_RepairVehicle.cs
index d5bc10b0..07272205 100644
--- a/Source/Vehicles/AI/JobDrivers/JobDriver_RepairVehicle.cs
+++ b/Source/Vehicles/AI/JobDrivers/JobDriver_RepairVehicle.cs
@@ -22,7 +22,7 @@ protected override void WorkComplete(Pawn actor)
{
if (!Vehicle.statHandler.ComponentsPrioritized.Any(c => c.HealthPercent < 1))
{
- Vehicle.Map.GetCachedMapComponent().Notify_VehicleRepaired(Vehicle);
+ MapComponentCache.GetComponent(Vehicle.Map).Notify_VehicleRepaired(Vehicle);
actor.records.Increment(RecordDefOf.ThingsRepaired);
actor.jobs.EndCurrentJob(JobCondition.Succeeded);
return;
diff --git a/Source/Vehicles/AI/JobDrivers/JobDriver_UpgradeVehicle.cs b/Source/Vehicles/AI/JobDrivers/JobDriver_UpgradeVehicle.cs
index 5f1be80f..511dc80b 100644
--- a/Source/Vehicles/AI/JobDrivers/JobDriver_UpgradeVehicle.cs
+++ b/Source/Vehicles/AI/JobDrivers/JobDriver_UpgradeVehicle.cs
@@ -13,7 +13,17 @@ public class JobDriver_UpgradeVehicle : JobDriver_WorkVehicle
protected override StatDef Stat => StatDefOf.ConstructionSpeed;
- protected override float TotalWork => Vehicle.CompUpgradeTree.NodeUnlocking.work;
+ protected override float TotalWork
+ {
+ get
+ {
+ if (Vehicle.CompUpgradeTree.upgrade.Removal)
+ {
+ return Vehicle.CompUpgradeTree.NodeUnlocking.work * 0.3f; //30% work cost for removing upgrades
+ }
+ return Vehicle.CompUpgradeTree.NodeUnlocking.work;
+ }
+ }
protected override float Work
{
diff --git a/Source/Vehicles/AI/JobDrivers/Toils/Toils_Board.cs b/Source/Vehicles/AI/JobDrivers/Toils/Toils_Board.cs
index cd7d7597..97cccb77 100644
--- a/Source/Vehicles/AI/JobDrivers/Toils/Toils_Board.cs
+++ b/Source/Vehicles/AI/JobDrivers/Toils/Toils_Board.cs
@@ -25,7 +25,7 @@ public static Toil BoardVehicle(Pawn pawnBoarding)
VehicleHandler handler = vehicle.bills.FirstOrDefault(b => b.pawnToBoard == pawnBoarding)?.handler;
if (handler is null)
{
- handler = vehicle.Map.GetCachedMapComponent().GetReservation(vehicle)?.ReservedHandler(pawnBoarding);
+ handler = MapComponentCache.GetComponent(vehicle.Map).GetReservation(vehicle)?.ReservedHandler(pawnBoarding);
if (handler is null)
{
Log.Error("Could not find assigned spot for " + pawnBoarding.LabelShort + " to board.");
diff --git a/Source/Vehicles/AI/JobDrivers/VehicleJobDriver.cs b/Source/Vehicles/AI/JobDrivers/VehicleJobDriver.cs
index 247fbcc5..ec29a101 100644
--- a/Source/Vehicles/AI/JobDrivers/VehicleJobDriver.cs
+++ b/Source/Vehicles/AI/JobDrivers/VehicleJobDriver.cs
@@ -23,7 +23,7 @@ public override bool TryMakePreToilReservations(bool errorOnFailed)
{
return false;
}
- VehicleReservationManager reservationManager = pawn.Map.GetCachedMapComponent();
+ VehicleReservationManager reservationManager = MapComponentCache.GetComponent(Vehicle.Map);
bool reserved = reservationManager.Reserve(Vehicle, pawn, job, JobCell);
return reserved;
}
diff --git a/Source/Vehicles/AI/JobGivers/JobGiver_SendSlavesToVehicle.cs b/Source/Vehicles/AI/JobGivers/JobGiver_SendSlavesToVehicle.cs
index d6f73b72..e953b6ab 100644
--- a/Source/Vehicles/AI/JobGivers/JobGiver_SendSlavesToVehicle.cs
+++ b/Source/Vehicles/AI/JobGivers/JobGiver_SendSlavesToVehicle.cs
@@ -17,7 +17,7 @@ protected override Job TryGiveJob(Pawn pawn)
if (pawn2 is null)
return null;
VehiclePawn vehicle = FindShipToDeposit(pawn, pawn2);
- VehicleHandler handler = vehicle.handlers.Find(x => x.role.handlingTypes == HandlingTypeFlags.None);
+ VehicleHandler handler = vehicle.handlers.Find(x => x.role.HandlingTypes == HandlingTypeFlags.None);
return new Job(JobDefOf.PrepareCaravan_GatherDownedPawns, pawn2)
{
count = 1
@@ -44,7 +44,7 @@ private Pawn FindPrisoner(Pawn pawn)
private VehiclePawn FindShipToDeposit(Pawn pawn, Pawn downedPawn)
{
List vehicles = pawn.GetLord().ownedPawns.Where(x => x is VehiclePawn).Cast().ToList();
- return vehicles.MaxBy(x => x.VehicleDef.properties.roles.Find(y => y.handlingTypes == HandlingTypeFlags.None).slots);
+ return vehicles.MaxBy(x => x.VehicleDef.properties.roles.Find(y => y.HandlingTypes == HandlingTypeFlags.None).Slots);
}
}
}
diff --git a/Source/Vehicles/AI/WorkGiver/WorkGiver_BringUpgradeMaterial.cs b/Source/Vehicles/AI/WorkGiver/WorkGiver_BringUpgradeMaterial.cs
index 2b653160..a42ef2d5 100644
--- a/Source/Vehicles/AI/WorkGiver/WorkGiver_BringUpgradeMaterial.cs
+++ b/Source/Vehicles/AI/WorkGiver/WorkGiver_BringUpgradeMaterial.cs
@@ -28,6 +28,10 @@ public override PathEndMode PathEndMode
public override bool JobAvailable(VehiclePawn vehicle)
{
+ if (!vehicle.Spawned)
+ {
+ return false;
+ }
if (vehicle.CompUpgradeTree == null)
{
return false;
@@ -40,6 +44,10 @@ public override bool JobAvailable(VehiclePawn vehicle)
{
return false;
}
+ if (!MapComponentCache.GetComponent(vehicle.Map).VehicleListed(vehicle, ReservationType.LoadUpgradeMaterials))
+ {
+ return false;
+ }
return !vehicle.CompUpgradeTree.StoredCostSatisfied;
}
@@ -80,7 +88,7 @@ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
Thing thing = FindThingToPack(vehicle, pawn);
if (thing != null)
{
- int countLeft = CountLeftToPack(vehicle, pawn, new ThingDefCount(thing.def, thing.stackCount));
+ int countLeft = CountLeftToPack(vehicle, pawn, new ThingDefCount(thing.def, vehicle.CompUpgradeTree.upgrade.node.MaterialsRequired(vehicle).FirstOrDefault(thingDefCountClass => thingDefCountClass.thingDef==thing.def).count));
int jobCount = Mathf.Min(thing.stackCount, countLeft);
if (jobCount > 0)
{
@@ -96,7 +104,7 @@ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
public override Thing FindThingToPack(VehiclePawn vehicle, Pawn pawn)
{
Thing result = null;
- IEnumerable thingDefs = ThingDefs(vehicle);
+ IEnumerable thingDefs = vehicle.CompUpgradeTree.upgrade.node.MaterialsRequired(vehicle);
if (thingDefs.NotNullAndAny())
{
foreach (ThingDefCount thingDefCount in thingDefs)
diff --git a/Source/Vehicles/Components/Rendering/Overlays/GraphicDataOverlay.cs b/Source/Vehicles/Components/Rendering/Overlays/GraphicDataOverlay.cs
index 9100d901..7c9e1cff 100644
--- a/Source/Vehicles/Components/Rendering/Overlays/GraphicDataOverlay.cs
+++ b/Source/Vehicles/Components/Rendering/Overlays/GraphicDataOverlay.cs
@@ -10,6 +10,8 @@ public class GraphicDataOverlay
[SliderValues(MinValue = 0, MaxValue = 360, RoundDecimalPlaces = 0, Increment = 1)]
public float rotation = 0;
+ public bool dynamicShadows;
+
public ComponentRendering component;
public bool renderUI = true;
diff --git a/Source/Vehicles/Components/Rendering/Overlays/GraphicOverlay.cs b/Source/Vehicles/Components/Rendering/Overlays/GraphicOverlay.cs
index ab468491..514804cd 100644
--- a/Source/Vehicles/Components/Rendering/Overlays/GraphicOverlay.cs
+++ b/Source/Vehicles/Components/Rendering/Overlays/GraphicOverlay.cs
@@ -10,9 +10,11 @@ public class GraphicOverlay : IMaterialCacheTarget
[TweakField]
public GraphicDataOverlay data;
- private VehicleDef vehicleDef;
- private VehiclePawn vehicle;
- private Graphic graphicInt;
+ private readonly VehicleDef vehicleDef;
+ private readonly VehiclePawn vehicle;
+
+ private Graphic graphic;
+ private Graphic_DynamicShadow graphicShadow;
public GraphicOverlay(GraphicDataOverlay graphicDataOverlay, VehicleDef vehicleDef)
{
@@ -27,6 +29,16 @@ public GraphicOverlay(GraphicDataOverlay graphicDataOverlay, VehiclePawn vehicle
this.vehicleDef = vehicle.VehicleDef;
this.vehicle.AddEvent(VehicleEventDefOf.Destroyed, OnDestroy);
+
+ if (data.dynamicShadows)
+ {
+ ShadowData shadowData = new ShadowData()
+ {
+ volume = new Vector3(data.graphicData.drawSize.x, 0, data.graphicData.drawSize.y),
+ offset = new Vector3(data.graphicData.drawOffset.x, 0, data.graphicData.drawOffset.z + 5),
+ };
+ graphicShadow = new Graphic_DynamicShadow(data.graphicData.Graphic.TexAt(Rot8.North), shadowData);
+ }
}
public int MaterialCount => vehicle?.MaterialCount ?? vehicleDef.MaterialCount;
@@ -35,11 +47,13 @@ public GraphicOverlay(GraphicDataOverlay graphicDataOverlay, VehiclePawn vehicle
public string Name => $"{vehicleDef.Name}_{data.graphicData.texPath}";
+ public Graphic_DynamicShadow ShadowGraphic => graphicShadow;
+
public Graphic Graphic
{
get
{
- if (graphicInt is null)
+ if (graphic is null)
{
if (vehicle != null && vehicle.Destroyed && !RGBMaterialPool.GetAll(this).NullOrEmpty())
{
@@ -61,24 +75,27 @@ public Graphic Graphic
RGBMaterialPool.CacheMaterialsFor(this);
graphicData.Init(this);
- graphicInt = graphicData.Graphic;
- var graphicRGB = graphicInt as Graphic_RGB;
+ graphic = graphicData.Graphic;
+ var graphicRGB = graphic as Graphic_RGB;
RGBMaterialPool.SetProperties(this, patternData, graphicRGB.TexAt, graphicRGB.MaskAt);
}
else
{
- graphicInt = ((GraphicData)graphicData).Graphic;
+ graphic = ((GraphicData)graphicData).Graphic;
}
}
- return graphicInt;
+ return graphic;
}
}
public void Notify_ColorChanged()
{
- PatternData patternData = vehicle?.patternData ?? VehicleMod.settings.vehicles.defaultGraphics.TryGetValue(vehicleDef.defName, new PatternData(vehicleDef.graphicData));
- RGBMaterialPool.SetProperties(this, patternData);
- graphicInt = null;
+ if (data.graphicData.shaderType.Shader.SupportsRGBMaskTex())
+ {
+ PatternData patternData = vehicle?.patternData ?? VehicleMod.settings.vehicles.defaultGraphics.TryGetValue(vehicleDef.defName, new PatternData(vehicleDef.graphicData));
+ RGBMaterialPool.SetProperties(this, patternData);
+ graphic = null;
+ }
}
public void OnDestroy()
@@ -88,6 +105,11 @@ public void OnDestroy()
public static GraphicOverlay Create(GraphicDataOverlay graphicDataOverlay, VehiclePawn vehicle)
{
+ if (!UnityData.IsInMainThread)
+ {
+ Log.Error($"Trying to create GraphicOverlay outside of the main thread.");
+ return null;
+ }
GraphicOverlay graphicOverlay = new GraphicOverlay(graphicDataOverlay, vehicle);
graphicDataOverlay.graphicData.shaderType ??= ShaderTypeDefOf.Cutout;
if (!VehicleMod.settings.main.useCustomShaders)
diff --git a/Source/Vehicles/Components/Rendering/Overlays/PawnOverlayRenderer.cs b/Source/Vehicles/Components/Rendering/Overlays/PawnOverlayRenderer.cs
index 1e835725..00d51655 100644
--- a/Source/Vehicles/Components/Rendering/Overlays/PawnOverlayRenderer.cs
+++ b/Source/Vehicles/Components/Rendering/Overlays/PawnOverlayRenderer.cs
@@ -1,18 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
+using HarmonyLib;
using UnityEngine;
using Verse;
using RimWorld;
using SmashTools;
+
namespace Vehicles
{
public class PawnOverlayRenderer
{
- private const float LayersTotalAllowed = 10;
-
- private static Listing_SplitColumns listing = new Listing_SplitColumns();
+ private Listing_SplitColumns listing = new Listing_SplitColumns();
[TweakField(SettingsType = UISettingsType.Checkbox)]
public bool showBody = true;
@@ -134,18 +135,19 @@ public float AngleFor(Rot8 rot)
public float LayerFor(Rot8 rot)
{
- return rot.AsInt switch
+ int rotLayer = rot.AsInt switch
{
- 0 => (layerNorth ?? layerSouth ?? layer) / LayersTotalAllowed,
- 1 => (layerEast ?? layerWest ?? layer) / LayersTotalAllowed,
- 2 => (layerSouth ?? layerNorth ?? layer) / LayersTotalAllowed,
- 3 => (layerWest ?? layerEast ?? layer) / LayersTotalAllowed,
- 4 => (layerNorthEast ?? layerNorthWest ?? layerNorth ?? layer) / LayersTotalAllowed,
- 5 => (layerSouthEast ?? layerSouthWest ?? layerSouth ?? layer) / LayersTotalAllowed,
- 6 => (layerSouthWest ?? layerSouthEast ?? layerSouth ?? layer) / LayersTotalAllowed,
- 7 => (layerNorthWest ?? layerNorthEast ?? layerNorth ?? layer) / LayersTotalAllowed,
+ 0 => (layerNorth ?? layerSouth ?? layer),
+ 1 => (layerEast ?? layerWest ?? layer),
+ 2 => (layerSouth ?? layerNorth ?? layer),
+ 3 => (layerWest ?? layerEast ?? layer),
+ 4 => (layerNorthEast ?? layerNorthWest ?? layerNorth ?? layer),
+ 5 => (layerSouthEast ?? layerSouthWest ?? layerSouth ?? layer),
+ 6 => (layerSouthWest ?? layerSouthEast ?? layerSouth ?? layer),
+ 7 => (layerNorthWest ?? layerNorthEast ?? layerNorth ?? layer),
_ => throw new NotImplementedException(),
};
+ return rotLayer * (Altitudes.AltInc / GraphicDataLayered.SubLayerCount);
}
public Vector3 DrawOffsetFor(Rot8 rot)
@@ -162,7 +164,7 @@ public Vector3 DrawOffsetFor(Rot8 rot)
7 => drawOffsetNorthWest ?? drawOffsetNorthEast?.MirrorHorizontal() ?? drawOffsetNorth?.RotatedBy(-45) ?? drawOffset.RotatedBy(rot.AsAngle),
_ => throw new NotImplementedException(),
};
- offset.y = LayerFor(rot);
+ offset.y += LayerFor(rot);
return offset;
}
diff --git a/Source/Vehicles/Components/Rendering/Overlays/VehicleGraphicOverlay.cs b/Source/Vehicles/Components/Rendering/Overlays/VehicleGraphicOverlay.cs
index c254cbd1..e9af3888 100644
--- a/Source/Vehicles/Components/Rendering/Overlays/VehicleGraphicOverlay.cs
+++ b/Source/Vehicles/Components/Rendering/Overlays/VehicleGraphicOverlay.cs
@@ -7,7 +7,7 @@
namespace Vehicles
{
- public class VehicleGraphicOverlay
+ public class VehicleGraphicOverlay //TODO 1.6 - Choose better name to indicate this is a component of VehiclePawn
{
public readonly VehiclePawn vehicle;
@@ -77,6 +77,7 @@ public void RemoveOverlays(string key)
foreach (GraphicOverlay graphicOverlay in extraOverlayLookup[key])
{
extraOverlays.Remove(graphicOverlay);
+ graphicOverlay.OnDestroy();
}
extraOverlayLookup.Remove(key);
}
@@ -149,6 +150,10 @@ public virtual void RenderGraphicOverlays(Vector3 drawPos, float angle, Rot8 rot
{
graphicOverlay.Graphic.DrawWorker(overlayDrawPos, rot, null, null, overlayAngle + extraAngle);
}
+ if (graphicOverlay.ShadowGraphic != null)
+ {
+ graphicOverlay.ShadowGraphic.DrawWorker(overlayDrawPos, rot, null, null, overlayAngle + extraAngle);
+ }
}
}
diff --git a/Source/Vehicles/Components/Rendering/VehicleRenderer.cs b/Source/Vehicles/Components/Rendering/VehicleRenderer.cs
index 030fba3a..959b8d79 100644
--- a/Source/Vehicles/Components/Rendering/VehicleRenderer.cs
+++ b/Source/Vehicles/Components/Rendering/VehicleRenderer.cs
@@ -18,7 +18,7 @@ public sealed class VehicleRenderer
public VehicleGraphicSet graphics;
- private Graphic_Shadow shadowGraphic;
+ //private Graphic_DynamicShadow shadowGraphic;
//FOR TESTING ONLY
private PawnFirefoamDrawer firefoamOverlays;
@@ -45,15 +45,15 @@ public void RenderPawnAt(Vector3 drawLoc, float angle, bool northSouthRotation)
if (vehicle.def.race.specialShadowData != null)
{
- if (shadowGraphic == null)
- {
- shadowGraphic = new Graphic_Shadow(vehicle.def.race.specialShadowData);
- }
- shadowGraphic.Draw(drawLoc, Rot4.North, vehicle, 0f);
+ //if (shadowGraphic == null)
+ //{
+ // shadowGraphic = new Graphic_DynamicShadow(vehicle.def.race.specialShadowData);
+ //}
+ //shadowGraphic.Draw(drawLoc, Rot4.North, vehicle, 0f);
}
- if (graphics.vehicle.VehicleGraphic != null && graphics.vehicle.VehicleGraphic.ShadowGraphic != null)
+ if (graphics.vehicle.VehicleGraphic?.ShadowGraphic != null)
{
- graphics.vehicle.VehicleGraphic.ShadowGraphic.Draw(drawLoc, Rot4.North, vehicle, 0f);
+ graphics.vehicle.VehicleGraphic.ShadowGraphic.Draw(drawLoc, vehicle.FullRotation, vehicle, 0f);
}
if (vehicle.Spawned && !vehicle.Dead)
{
@@ -84,7 +84,7 @@ private void RenderPawnInternal(Vector3 rootLoc, float angle, bool northSouthRot
Rot8 vehicleRot = new Rot8(bodyFacing, angle);
Mesh mesh = graphics.vehicle.VehicleGraphic.MeshAtFull(vehicleRot);
List list = graphics.MatsBodyBaseAt(vehicleRot);
-
+
for (int i = 0; i < list.Count; i++)
{
GenDraw.DrawMeshNowOrLater(mesh, aboveBodyPos, quaternion, list[i], false);
diff --git a/Source/Vehicles/Components/Vehicles/Health/ComponentHitbox.cs b/Source/Vehicles/Components/Vehicles/Health/ComponentHitbox.cs
index 97d6d28d..e7081ab3 100644
--- a/Source/Vehicles/Components/Vehicles/Health/ComponentHitbox.cs
+++ b/Source/Vehicles/Components/Vehicles/Health/ComponentHitbox.cs
@@ -44,14 +44,14 @@ public void Initialize(VehicleDef def)
Empty = false;
CellRect rect = def.VehicleRect(new IntVec3(0, 0, 0), Rot4.North);
List cells;
- if (side == VehicleComponentPosition.Body) //TODO - Remove BodyNoOverlap in 1.5
+ if (side == VehicleComponentPosition.Body)
{
cells = rect.Cells.ToList();
}
- else if (side == VehicleComponentPosition.BodyNoOverlap)
+ else if (side == VehicleComponentPosition.BodyNoOverlap) //TODO 1.6 - Remove BodyNoOverlap
{
cells = rect.Cells.ToList();
- Log.Warning($"[{def}] BodyNoOverlap is obsolete, specify the cells directly or use Body. This option will be removed in 1.5");
+ Log.Warning($"[{def}] BodyNoOverlap is obsolete, specify the cells directly or use Body. This option will be removed in 1.6");
}
else if (side != VehicleComponentPosition.Empty)
{
diff --git a/Source/Vehicles/Components/Vehicles/Health/StatWorkers/VehicleStatWorker.cs b/Source/Vehicles/Components/Vehicles/Health/StatWorkers/VehicleStatWorker.cs
index e38b6d94..0446e72e 100644
--- a/Source/Vehicles/Components/Vehicles/Health/StatWorkers/VehicleStatWorker.cs
+++ b/Source/Vehicles/Components/Vehicles/Health/StatWorkers/VehicleStatWorker.cs
@@ -15,6 +15,18 @@ public class VehicleStatWorker
protected Dictionary baseValues;
protected List statParts;
+ private static readonly Gradient gradient = new Gradient()
+ {
+ colorKeys = new[] { new GradientColorKey(Color.gray, 0),
+ new GradientColorKey(TexData.RedReadable, 0.25f),
+ new GradientColorKey(TexData.SevereDamage, 0.4f),
+ new GradientColorKey(TexData.ModerateDamage, 0.7f),
+ new GradientColorKey(TexData.MinorDamage, 0.75f),
+ new GradientColorKey(TexData.WorkingCondition, 1),
+ new GradientColorKey(TexData.Enhanced, 1.01f) //greater than 101% max efficiency
+ }
+ };
+
public VehicleStatWorker()
{
}
@@ -276,7 +288,7 @@ public virtual float DrawVehicleStat(Rect leftRect, float curY, VehiclePawn vehi
float baseValue = GetBaseValue(vehicle.VehicleDef);
if (statDef.operationType > EfficiencyOperationType.None)
{
- Color effColor = baseValue == 0 ? TexData.WorkingCondition : VehicleComponent.gradient.Evaluate(GetValue(vehicle) / baseValue);
+ Color effColor = baseValue == 0 ? TexData.WorkingCondition : gradient.Evaluate(GetValue(vehicle) / baseValue);
Widgets.Label(new Rect(leftRect.width * 0.65f, curY, leftRect.width * 0.35f, 30f), StatValueFormatted(vehicle).Colorize(effColor));
Rect rect2 = new Rect(0f, curY, leftRect.width, 20f);
if (Mouse.IsOver(rect2))
diff --git a/Source/Vehicles/Components/Vehicles/Health/VehicleComponent.cs b/Source/Vehicles/Components/Vehicles/Health/VehicleComponent.cs
index 006d6661..a2ea201a 100644
--- a/Source/Vehicles/Components/Vehicles/Health/VehicleComponent.cs
+++ b/Source/Vehicles/Components/Vehicles/Health/VehicleComponent.cs
@@ -25,7 +25,7 @@ public class VehicleComponent : IExposable, ITweakFields
public IndicatorDef indicator;
public Color highlightColor = Color.white;
- public static Gradient gradient;
+ public VehiclePartDepth? depthOverride;
public VehicleComponent(VehiclePawn vehicle)
{
@@ -44,7 +44,7 @@ public VehicleComponent(VehiclePawn vehicle)
public Dictionary AddHealthModifiers { get; private set; } = new Dictionary();
- public Color EfficiencyColor => gradient.Evaluate(Efficiency);
+ public VehiclePartDepth Depth => depthOverride ?? props.depth;
string ITweakFields.Category => props.key;
@@ -179,25 +179,30 @@ public virtual void ReduceDamageFromArmor(ref DamageInfo dinfo, out Penetration
///
///
/// armor rating %
- public float ArmorRating(DamageArmorCategoryDef armorCategoryDef, out bool upgraded)
+ public float ArmorRating(DamageArmorCategoryDef armorCategoryDef, out float upgraded)
{
- upgraded = false;
+ float baseValue = vehicle.GetStatValue(armorCategoryDef.armorRatingStat);
+
+ upgraded = 0;
if (!SetArmorModifiers.NullOrEmpty())
{
foreach (List statModifiers in SetArmorModifiers.Values)
{
if (TryGetModifier(statModifiers, out float setValue))
{
- upgraded = true;
+ upgraded = setValue - baseValue;
return setValue;
}
}
}
- float value = vehicle.statHandler.GetUpgradeableStatValue(armorCategoryDef.armorRatingStat);
+
+ float value = baseValue + vehicle.statHandler.GetUpgradeableStatValue(armorCategoryDef.armorRatingStat);
+
StatModifier armorModifier = props.armor?.FirstOrDefault(rating => rating.stat == armorCategoryDef.armorRatingStat);
if (armorModifier != null)
{
- value = armorModifier.value;
+ baseValue = armorModifier.value; //Part-specific armor does not apply vehicle-wide armor upgrades
+ value = baseValue;
}
if (!AddArmorModifiers.NullOrEmpty())
{
@@ -205,11 +210,11 @@ public float ArmorRating(DamageArmorCategoryDef armorCategoryDef, out bool upgra
{
if (TryGetModifier(statModifiers, out float addValue))
{
- upgraded = true;
value += addValue;
}
}
}
+ upgraded = value - baseValue;
return value;
bool TryGetModifier(List statModifiers, out float value)
@@ -241,17 +246,6 @@ public virtual void Initialize(VehicleComponentProperties props)
this.props = props;
indicator = props.reactors?.FirstOrDefault(reactor => reactor.indicator != null)?.indicator;
highlightColor = props.reactors?.FirstOrDefault()?.highlightColor ?? Color.white;
- gradient = new Gradient()
- {
- colorKeys = new[] { new GradientColorKey(Color.gray, props.efficiency[0].x),
- new GradientColorKey(TexData.RedReadable, props.efficiency[1].x),
- new GradientColorKey(TexData.SevereDamage, props.efficiency[2].x),
- new GradientColorKey(TexData.ModerateDamage, props.efficiency[3].x),
- new GradientColorKey(TexData.MinorDamage, props.efficiency[4].x),
- new GradientColorKey(TexData.WorkingCondition, props.efficiency[5].x),
- new GradientColorKey(TexData.Enhanced, props.efficiency[5].x + 0.01f) //greater than 101% max efficiency
- }
- };
}
public virtual void ExposeData()
diff --git a/Source/Vehicles/Components/Vehicles/Health/VehicleStatDef.cs b/Source/Vehicles/Components/Vehicles/Health/VehicleStatDef.cs
index ba027364..3b6e7139 100644
--- a/Source/Vehicles/Components/Vehicles/Health/VehicleStatDef.cs
+++ b/Source/Vehicles/Components/Vehicles/Health/VehicleStatDef.cs
@@ -30,6 +30,7 @@ public class VehicleStatDef : Def, IDefIndex
public ToStringStyle toStringStyle = ToStringStyle.Integer;
public ToStringNumberSense toStringNumberSense = ToStringNumberSense.Absolute;
public EfficiencyOperationType operationType = EfficiencyOperationType.None;
+ public UpgradeEffectType upgradeEffectType = UpgradeEffectType.Positive;
public SimpleCurve postProcessCurve;
public List postProcessStatFactors;
diff --git a/Source/Vehicles/Components/Vehicles/Health/VehicleStatHandler.cs b/Source/Vehicles/Components/Vehicles/Health/VehicleStatHandler.cs
index 0a964829..4ef1a87d 100644
--- a/Source/Vehicles/Components/Vehicles/Health/VehicleStatHandler.cs
+++ b/Source/Vehicles/Components/Vehicles/Health/VehicleStatHandler.cs
@@ -168,13 +168,17 @@ public float GetStatOffset(VehicleStatDef vehicleStatDef)
return 0;
}
- public float GetStatOffset(StatUpgradeCategoryDef upgradeCategoryDef)
+ public float GetStatOffset(StatUpgradeCategoryDef upgradeCategoryDef, float value)
{
if (categoryOffsets.TryGetValue(upgradeCategoryDef, out StatOffset statOffset))
{
- return statOffset.Offset;
+ if (statOffset.TryGetOverride(out float setValue))
+ {
+ return setValue;
+ }
+ return value + statOffset.Offset;
}
- return 0;
+ return value;
}
public float GetStatValue(VehicleStatDef vehicleStatDef)
@@ -199,7 +203,7 @@ public void SubtractUpgradeableStatValue(StatDef statDef, float value)
baseStatOffsets[statDef] = new StatOffset(vehicle, statDef);
statOffset = baseStatOffsets[statDef];
}
- statOffset.Offset += value;
+ statOffset.Offset -= value;
}
public void SetUpgradeableStatValue(string key, StatDef statDef, float value)
@@ -228,7 +232,7 @@ public float GetUpgradeableStatValue(StatDef statDef)
{
return statOffset.Offset;
}
- return vehicle.GetStatValue(statDef);
+ return 0;
}
public void MarkStatDirty(VehicleStatDef statDef)
@@ -526,17 +530,17 @@ private void ApplyDamageToComponent(DamageInfo dinfo, IntVec2 hitCell, StringBui
report?.AppendLine($"components=({string.Join(",", components.Select(c => c.props.label))})");
report?.AppendLine($"hitDepth = {hitDepth}");
//If no components at hit cell, fallthrough to internal
- var externalComponentsAtHitDepth = components.Where(comp => comp.props.depth == hitDepth && comp.HealthPercent > 0);
+ var externalComponentsAtHitDepth = components.Where(comp => comp.Depth == hitDepth && comp.HealthPercent > 0);
report?.AppendLine($"components at hitDepth {hitDepth}: ({string.Join(",", externalComponentsAtHitDepth.Select(comp => comp.props.label))})");
if (!externalComponentsAtHitDepth.TryRandomElementByWeight((component) => component.props.hitWeight, out component))
{
report?.AppendLine($"No components found. Hitting internal parts.");
hitDepth = VehicleComponent.VehiclePartDepth.Internal;
- var internalComponentsAtHitDepth = components.Where(comp => comp.props.depth == hitDepth && comp.HealthPercent > 0);
+ var internalComponentsAtHitDepth = components.Where(comp => comp.Depth == hitDepth && comp.HealthPercent > 0);
if (!internalComponentsAtHitDepth.TryRandomElementByWeight((component) => component.props.hitWeight, out component))
{
//If depth = internal then pick random internal component even if it does not have a hitbox
- component = this.components.Where(comp => comp.props.depth == hitDepth && comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
+ component = this.components.Where(comp => comp.Depth == hitDepth && comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
//If no internal components, pick random component w/ health
component ??= this.components.Where(comp => comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
if (component is null)
@@ -559,7 +563,7 @@ private void ApplyDamageToComponent(DamageInfo dinfo, IntVec2 hitCell, StringBui
report?.AppendLine($"No components found. Hitting internal parts.");
hitDepth = VehicleComponent.VehiclePartDepth.Internal;
//If depth = internal then pick random internal component even if it does not have a hitbox
- component = this.components.Where(comp => comp.props.depth == hitDepth && comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
+ component = this.components.Where(comp => comp.Depth == hitDepth && comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
//If no internal components, pick random component w/ health
component ??= this.components.Where(comp => comp.HealthPercent > 0).RandomElementByWeightWithFallback((component) => component.props.hitWeight);
if (component is null)
@@ -672,10 +676,10 @@ private bool HitPawn(DamageInfo dinfo, VehicleComponent.VehiclePartDepth hitDept
}
}
}
- if (handler != null && handler.handlers.Count > 0 && Rand.Chance(handler.role.chanceToHit * multiplier))
+ if (handler != null && handler.handlers.Count > 0 && Rand.Chance(handler.role.ChanceToHit * multiplier))
{
hitPawn = handler.handlers.InnerListForReading.RandomElement();
- report?.AppendLine($"Hitting {handler} with chance {handler.role.chanceToHit * multiplier}");
+ report?.AppendLine($"Hitting {handler} with chance {handler.role.ChanceToHit * multiplier}");
hitPawn.TakeDamage(dinfo);
return true;
}
@@ -684,7 +688,7 @@ private bool HitPawn(DamageInfo dinfo, VehicleComponent.VehiclePartDepth hitDept
private bool TrySelectHandler(IntVec2 cell, out VehicleHandler handler, bool exposed = false)
{
- handler = vehicle.handlers.FirstOrDefault(handler => handler.role.hitbox != null && handler.role.hitbox.Contains(cell) && handler.handlers.Count > 0 && handler.role.exposed == exposed);
+ handler = vehicle.handlers.FirstOrDefault(handler => handler.role.Hitbox != null && handler.role.Hitbox.Contains(cell) && handler.handlers.Count > 0 && handler.role.Exposed == exposed);
return handler != null;
}
@@ -727,7 +731,7 @@ public void DrawHitbox(VehicleComponent component)
hitboxHighlightCells.Add(new IntVec3(vehicle.Position.x + rotatedCell.x, 0, vehicle.Position.z + rotatedCell.z));
}
}
- else if (component.props.depth == VehicleComponent.VehiclePartDepth.External) //Dont render Internal components without a hitbox
+ else if (component.Depth == VehicleComponent.VehiclePartDepth.External) //Dont render Internal components without a hitbox
{
hitboxHighlightCells.AddRange(vehicle.OccupiedRect());
}
diff --git a/Source/Vehicles/Components/Vehicles/VehicleDef.cs b/Source/Vehicles/Components/Vehicles/VehicleDef.cs
index 308bcee0..9b877ac7 100644
--- a/Source/Vehicles/Components/Vehicles/VehicleDef.cs
+++ b/Source/Vehicles/Components/Vehicles/VehicleDef.cs
@@ -8,6 +8,7 @@
using RimWorld;
using RimWorld.Planet;
using SmashTools;
+using static Vehicles.VehicleUpgrade;
namespace Vehicles
{
@@ -62,6 +63,7 @@ public class VehicleDef : ThingDef, IDefIndex, IMaterialCacheTarget,
// : SoundDef
public List> soundSustainersOnEvent = new List>();
+ //TODO 1.6 - refactor to container class for cleaner xml input
public Dictionary>> events = new Dictionary>>();
public List designatorTypes = new List();
@@ -326,6 +328,49 @@ public Vector2 ScaleDrawRatio(GraphicData graphicData, Rot4 rot, Vector2 size, f
return new Vector2(width, height);
}
+ public VehicleRole CreateRole(string roleKey)
+ {
+ if (!properties.roles.NullOrEmpty())
+ {
+ foreach (VehicleRole vehicleRole in properties.roles)
+ {
+ if (vehicleRole.key == roleKey)
+ {
+ return new VehicleRole(vehicleRole);
+ }
+ }
+ }
+ if (GetCompProperties() is CompProperties_UpgradeTree compPropertiesUpgradeTree)
+ {
+ foreach (UpgradeNode node in compPropertiesUpgradeTree.def.nodes)
+ {
+ if (!node.upgrades.NullOrEmpty())
+ {
+ foreach (Upgrade upgrade in node.upgrades)
+ {
+ if (upgrade is VehicleUpgrade vehicleUpgrade)
+ {
+ if (!vehicleUpgrade.roles.NullOrEmpty())
+ {
+ foreach (RoleUpgrade roleUpgrade in vehicleUpgrade.roles)
+ {
+ if (roleUpgrade.key == roleKey && roleUpgrade.editKey.NullOrEmpty())
+ {
+ return RoleUpgrade.RoleFromUpgrade(roleUpgrade);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Log.Error($"Unable to create role {roleKey}. Matching VehicleRole not found in VehicleDef ({defName}) or UpgradeTreeDef ({compPropertiesUpgradeTree.def.defName})");
+ return null;
+ }
+ Log.Error($"Unable to create role {roleKey}. Matching VehicleRole not found in VehicleDef ({defName}).");
+ return null;
+ }
+
///
/// Retrieve all 's for this VehicleDef
///
diff --git a/Source/Vehicles/Components/Vehicles/VehicleDrawProperties.cs b/Source/Vehicles/Components/Vehicles/VehicleDrawProperties.cs
index d7516e8c..9e007010 100644
--- a/Source/Vehicles/Components/Vehicles/VehicleDrawProperties.cs
+++ b/Source/Vehicles/Components/Vehicles/VehicleDrawProperties.cs
@@ -45,10 +45,10 @@ public void PostDefDatabase(VehicleDef vehicleDef)
foreach (GraphicDataOverlay graphicDataOverlay in graphicOverlays)
{
GraphicOverlay graphicOverlay = GraphicOverlay.Create(graphicDataOverlay, vehicleDef);
+ graphicOverlay.data.graphicData.RecacheLayerOffsets();
overlays.Add(graphicOverlay);
}
});
-
}
public Vector3 DisplayOffsetForRot(Rot4 rot)
diff --git a/Source/Vehicles/Components/Vehicles/VehicleHandler.cs b/Source/Vehicles/Components/Vehicles/VehicleHandler.cs
index 8f101409..73e6612c 100644
--- a/Source/Vehicles/Components/Vehicles/VehicleHandler.cs
+++ b/Source/Vehicles/Components/Vehicles/VehicleHandler.cs
@@ -5,9 +5,13 @@
using RimWorld;
using RimWorld.Planet;
using SmashTools;
+using UnityEngine;
namespace Vehicles
{
+ ///
+ /// Handles instance behavior of a vehicle's role.
+ ///
public class VehicleHandler : IExposable, ILoadReferenceable, IThingHolderPawnOverlayer
{
public ThingOwner handlers;
@@ -20,10 +24,7 @@ public class VehicleHandler : IExposable, ILoadReferenceable, IThingHolderPawnOv
public VehicleHandler()
{
- if (handlers is null)
- {
- handlers = new ThingOwner(this, false, LookMode.Deep);
- }
+ handlers ??= new ThingOwner(this, false, LookMode.Deep);
}
public VehicleHandler(VehiclePawn vehicle) : this()
@@ -32,31 +33,31 @@ public VehicleHandler(VehiclePawn vehicle) : this()
this.vehicle = vehicle;
}
- public VehicleHandler(VehiclePawn vehicle, VehicleRole newRole) : this(vehicle)
+ public VehicleHandler(VehiclePawn vehicle, VehicleRole role) : this(vehicle)
{
- role = new VehicleRole(newRole);
+ this.role = new VehicleRole(role); //Role must be instance based for upgrades to modify data
roleKey = role.key;
}
public IThingHolder ParentHolder => vehicle;
- Rot4 IThingHolderPawnOverlayer.PawnRotation => role.pawnRenderer?.RotFor(vehicle.FullRotation) ?? Rot4.South;
+ Rot4 IThingHolderPawnOverlayer.PawnRotation => role.PawnRenderer?.RotFor(vehicle.FullRotation) ?? Rot4.South;
- float IThingHolderWithDrawnPawn.HeldPawnDrawPos_Y => vehicle.DrawPos.y + role.pawnRenderer.LayerFor(vehicle.FullRotation);
+ float IThingHolderWithDrawnPawn.HeldPawnDrawPos_Y => vehicle.DrawPos.y + role.PawnRenderer.LayerFor(vehicle.FullRotation);
- float IThingHolderWithDrawnPawn.HeldPawnBodyAngle => role.pawnRenderer.AngleFor(vehicle.FullRotation);
+ float IThingHolderWithDrawnPawn.HeldPawnBodyAngle => role.PawnRenderer.AngleFor(vehicle.FullRotation);
PawnPosture IThingHolderWithDrawnPawn.HeldPawnPosture => PawnPosture.LayingInBedFaceUp;
- bool IThingHolderPawnOverlayer.ShowBody => role.pawnRenderer.showBody;
+ bool IThingHolderPawnOverlayer.ShowBody => role.PawnRenderer.showBody;
- public bool RequiredForMovement => role.handlingTypes.HasFlag(HandlingTypeFlags.Movement);
+ public bool RequiredForMovement => role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement);
public bool RoleFulfilled
{
get
{
- bool minRequirement = role != null && handlers.Count >= role.slotsToOperate;
+ bool minRequirement = role != null && handlers.Count >= role.SlotsToOperate;
if (!minRequirement)
{
return false;
@@ -69,7 +70,7 @@ public bool RoleFulfilled
operationalCount++;
}
}
- return operationalCount >= role.slotsToOperate;
+ return operationalCount >= role.SlotsToOperate;
}
}
@@ -78,7 +79,7 @@ public bool AreSlotsAvailable
get
{
bool reservation = vehicle.Map?.GetCachedMapComponent().CanReserve(vehicle, null, this) ?? true;
- return role != null && reservation && handlers.Count < role.slots;
+ return role != null && reservation && handlers.Count < role.Slots;
}
}
@@ -112,7 +113,7 @@ public bool AreSlotsAvailable
public bool CanOperateRole(Pawn pawn)
{
- if (role.handlingTypes > HandlingTypeFlags.None)
+ if (role.HandlingTypes > HandlingTypeFlags.None)
{
bool manipulation = pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation);
bool downed = pawn.Downed;
@@ -126,11 +127,13 @@ public bool CanOperateRole(Pawn pawn)
public void RenderPawns()
{
- if (role.pawnRenderer != null)
+ if (role.PawnRenderer != null)
{
foreach (Pawn pawn in handlers)
{
- pawn.Drawer.renderer.RenderPawnAt(vehicle.DrawPos + role.pawnRenderer.DrawOffsetFor(vehicle.FullRotation), role.pawnRenderer.RotFor(vehicle.FullRotation));
+ Vector3 position = vehicle.DrawPos + role.PawnRenderer.DrawOffsetFor(vehicle.FullRotation);
+ Rot4 rot = role.PawnRenderer.RotFor(vehicle.FullRotation);
+ pawn.Drawer.renderer.RenderPawnAt(position, rotOverride: rot);
}
}
}
@@ -188,12 +191,17 @@ public void ExposeData()
}
Scribe_Deep.Look(ref handlers, nameof(handlers), new object[] { this });
- if (Scribe.mode == LoadSaveMode.ResolvingCrossRefs)
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
- role = vehicle.VehicleDef.properties.roles.FirstOrDefault(role => role.key == roleKey);
+ role = vehicle.VehicleDef.CreateRole(roleKey);
if (role is null)
{
- Log.Error($"Could not load VehicleRole from {roleKey}. Was role removed or name changed?");
+ Log.Error($"Unable to load role={roleKey}. Creating empty role to avoid game-breaking issues.");
+ role ??= new VehicleRole()
+ {
+ key = $"{roleKey}_INVALID",
+ label = $"{roleKey} (INVALID)",
+ };
}
}
}
diff --git a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn.cs b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn.cs
index 5da27825..9f7f84d4 100644
--- a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn.cs
+++ b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn.cs
@@ -12,10 +12,11 @@
using Verse.AI;
using Verse.AI.Group;
using SmashTools;
+using SmashTools.Animations;
namespace Vehicles
{
- public partial class VehiclePawn : Pawn, IInspectable, IAnimationTarget, IEventManager, IMaterialCacheTarget
+ public partial class VehiclePawn : Pawn, IInspectable, IAnimationTarget, IAnimator, IEventManager, IMaterialCacheTarget
{
public bool Initialized { get; private set; }
@@ -121,7 +122,7 @@ private void InitializeVehicle()
//navigationCategory = VehicleDef.defaultNavigation;
- if (VehicleDef.properties.roles != null && VehicleDef.properties.roles.Count > 0)
+ if (!VehicleDef.properties.roles.NullOrEmpty())
{
foreach (VehicleRole role in VehicleDef.properties.roles)
{
@@ -172,6 +173,7 @@ private void GenerateInventory()
/// Called regardless if vehicle is spawned or unspawned. Responsible for important variables being set that may be called even for unspawned vehicles
protected virtual void PostLoad()
{
+ this.RegisterEvents(); //Events must be registered before comp post loads, SpawnSetup won't trigger register in this case
RegenerateUnsavedComponents();
RecacheComponents();
RecachePawnCount();
@@ -264,13 +266,13 @@ public override void ExposeData()
Scribe_Values.Look(ref crashLanded, nameof(crashLanded));
Scribe_Deep.Look(ref patternData, nameof(patternData));
- Scribe_Defs.Look(ref retexture, nameof(retexture));
+ Scribe_Defs.Look(ref retextureDef, nameof(retextureDef));
Scribe_Deep.Look(ref patternToPaint, nameof(patternToPaint));
if (!VehicleMod.settings.main.useCustomShaders)
{
patternData = new PatternData(VehicleDef.graphicData.color, VehicleDef.graphicData.colorTwo, VehicleDef.graphicData.colorThree, PatternDefOf.Default, Vector2.zero, 0);
- retexture = null;
+ retextureDef = null;
patternToPaint = null;
}
diff --git a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Combat.cs b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Combat.cs
index 8f700058..b2e83951 100644
--- a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Combat.cs
+++ b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Combat.cs
@@ -14,8 +14,8 @@ public float PawnCollisionMultiplier
get
{
float multiplier = SettingsCache.TryGetValue(VehicleDef, typeof(VehicleProperties), nameof(VehicleProperties.pawnCollisionMultiplier), VehicleDef.properties.pawnCollisionMultiplier);
- float offset = statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.PawnCollisionMultiplier);
- return multiplier + offset;
+ multiplier = statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.PawnCollisionMultiplier, multiplier);
+ return multiplier;
}
}
@@ -24,8 +24,8 @@ public float PawnCollisionRecoilMultiplier
get
{
float multiplier = SettingsCache.TryGetValue(VehicleDef, typeof(VehicleProperties), nameof(VehicleProperties.pawnCollisionRecoilMultiplier), VehicleDef.properties.pawnCollisionRecoilMultiplier); ;
- float offset = statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.PawnCollisionRecoilMultiplier);
- return multiplier + offset;
+ multiplier = statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.PawnCollisionRecoilMultiplier, multiplier);
+ return multiplier;
}
}
diff --git a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Handlers.cs b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Handlers.cs
index 39424e30..0836c94e 100644
--- a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Handlers.cs
+++ b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Handlers.cs
@@ -35,7 +35,7 @@ public bool MovementHandlerAvailable
{
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement) && handler.handlers.Count < handler.role.slotsToOperate)
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement) && handler.handlers.Count < handler.role.SlotsToOperate)
{
return false;
}
@@ -51,9 +51,9 @@ public int PawnCountToOperate
int pawnCount = 0;
foreach (VehicleRole role in VehicleDef.properties.roles)
{
- if (role.handlingTypes.HasFlag(HandlingTypeFlags.Movement))
+ if (role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement))
{
- pawnCount += role.slotsToOperate;
+ pawnCount += role.SlotsToOperate;
}
}
return pawnCount;
@@ -67,7 +67,7 @@ public int PawnCountToOperateLeft
int pawnsMounted = 0;
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement))
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement))
{
pawnsMounted += handler.handlers.Count;
}
@@ -86,7 +86,7 @@ public bool CanMoveWithOperators
}
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement) && !handler.RoleFulfilled)
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement) && !handler.RoleFulfilled)
{
return false;
}
@@ -104,7 +104,7 @@ public List AllCrewAboard
{
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement))
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement))
{
crewOnShip.AddRange(handler.handlers);
}
@@ -121,7 +121,7 @@ public List AllCannonCrew
List weaponCrewOnShip = new List();
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Turret))
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Turret))
{
weaponCrewOnShip.AddRange(handler.handlers);
}
@@ -139,7 +139,7 @@ public List Passengers
{
foreach (VehicleHandler handler in handlers)
{
- if (handler.role.handlingTypes == HandlingTypeFlags.None)
+ if (handler.role.HandlingTypes == HandlingTypeFlags.None)
{
passengers.AddRange(handler.handlers);
}
@@ -173,7 +173,7 @@ public int SeatsAvailable
int x = 0;
foreach (VehicleHandler handler in handlers)
{
- x += handler.role.slots - handler.handlers.Count;
+ x += handler.role.Slots - handler.handlers.Count;
}
return x;
}
@@ -186,7 +186,7 @@ public int TotalSeats
int x = 0;
foreach (VehicleHandler handler in handlers)
{
- x += handler.role.slots;
+ x += handler.role.Slots;
}
return x;
}
@@ -209,6 +209,7 @@ public void RecachePawnCount()
}
}
+ [Obsolete("Use AddRole instead", true)] //TODO 1.6 - Remove
public void AddHandlers(List handlerList)
{
if (handlerList.NullOrEmpty()) return;
@@ -217,7 +218,7 @@ public void AddHandlers(List handlerList)
VehicleHandler existingHandler = handlers.FirstOrDefault(h => h == handler);
if (existingHandler != null)
{
- existingHandler.role.turretIds.AddRange(handler.role.turretIds);
+ existingHandler.role.TurretIds.AddRange(handler.role.TurretIds);
}
else
{
@@ -227,6 +228,7 @@ public void AddHandlers(List handlerList)
}
}
+ [Obsolete("Use RemoveHandler instead", true)] //TODO 1.6 - Remove
public void RemoveHandlers(List handlerList)
{
if (handlerList.NullOrEmpty()) return;
@@ -236,18 +238,62 @@ public void RemoveHandlers(List handlerList)
}
}
+ public void AddRole(VehicleRole role)
+ {
+ role.ResolveReferences(VehicleDef);
+ handlers.Add(new VehicleHandler(this, role));
+ }
+
+ public void RemoveRole(VehicleRole role)
+ {
+ DisembarkAll(); //Temporary measure to avoid the destruction of all pawns within the role being removed
+ for (int i = handlers.Count - 1; i >= 0; i--)
+ {
+ VehicleHandler handler = handlers[i];
+ if (handler.role.key == role.key)
+ {
+ handlers.RemoveAt(i);
+ }
+ }
+ }
+
+ public void RemoveRole(string roleKey)
+ {
+ DisembarkAll(); //Temporary measure to avoid the destruction of all pawns within the role being removed
+ for (int i = handlers.Count - 1; i >= 0; i--)
+ {
+ VehicleHandler handler = handlers[i];
+ if (handler.role.key == roleKey)
+ {
+ handlers.RemoveAt(i);
+ }
+ }
+ }
+
+ public VehicleHandler GetHandler(string roleKey)
+ {
+ foreach (VehicleHandler handler in handlers)
+ {
+ if (handler.role.key == roleKey)
+ {
+ return handler;
+ }
+ }
+ return null;
+ }
+
public List GetAllHandlersMatch(HandlingTypeFlags? handlingTypeFlag, string turretKey = "")
{
if (handlingTypeFlag is null)
{
- return handlers.Where(handler => handler.role.handlingTypes == HandlingTypeFlags.None).ToList();
+ return handlers.Where(handler => handler.role.HandlingTypes == HandlingTypeFlags.None).ToList();
}
- return handlers.FindAll(x => x.role.handlingTypes.HasFlag(handlingTypeFlag) && (handlingTypeFlag != HandlingTypeFlags.Turret || (!x.role.turretIds.NullOrEmpty() && x.role.turretIds.Contains(turretKey))));
+ return handlers.FindAll(x => x.role.HandlingTypes.HasFlag(handlingTypeFlag) && (handlingTypeFlag != HandlingTypeFlags.Turret || (!x.role.TurretIds.NullOrEmpty() && x.role.TurretIds.Contains(turretKey))));
}
public List GetPriorityHandlers(HandlingTypeFlags? handlingTypeFlag = null)
{
- return handlers.Where(h => h.role.handlingTypes > HandlingTypeFlags.None && (handlingTypeFlag is null || h.role.handlingTypes.HasFlag(handlingTypeFlag.Value))).ToList();
+ return handlers.Where(h => h.role.HandlingTypes > HandlingTypeFlags.None && (handlingTypeFlag is null || h.role.HandlingTypes.HasFlag(handlingTypeFlag.Value))).ToList();
}
public VehicleHandler GetHandlersMatch(Pawn pawn)
@@ -258,8 +304,8 @@ public VehicleHandler GetHandlersMatch(Pawn pawn)
//REDO - cleanup
public VehicleHandler NextAvailableHandler(HandlingTypeFlags? handlingTypeFlag = null, bool priorityHandlers = false)
{
- IEnumerable prioritizedHandlers = priorityHandlers ? handlers.Where(h => h.role.handlingTypes > HandlingTypeFlags.None) : handlers;
- IEnumerable filteredHandlers = handlingTypeFlag is null ? prioritizedHandlers : prioritizedHandlers.Where(h => h.role.handlingTypes.HasFlag(handlingTypeFlag));
+ IEnumerable prioritizedHandlers = priorityHandlers ? handlers.Where(h => h.role.HandlingTypes > HandlingTypeFlags.None) : handlers;
+ IEnumerable filteredHandlers = handlingTypeFlag is null ? prioritizedHandlers : prioritizedHandlers.Where(h => h.role.HandlingTypes.HasFlag(handlingTypeFlag));
foreach (VehicleHandler handler in filteredHandlers)
{
if (handler.AreSlotsAvailable)
@@ -496,10 +542,10 @@ public static void TrySatisfyPawnNeeds(Pawn pawn)
}
break;
case Need_Comfort _:
- need.CurLevel = 0.5f; //TODO - add comfort factor for roles
+ need.CurLevel = handler.role.Comfort; //TODO - add comfort factor for roles
break;
case Need_Outdoors _:
- if (handler == null || handler.role.exposed)
+ if (handler == null || handler.role.Exposed)
{
need.NeedInterval();
}
diff --git a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Health.cs b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Health.cs
index 6cdb3329..c922c218 100644
--- a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Health.cs
+++ b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Health.cs
@@ -29,8 +29,6 @@ public partial class VehiclePawn
public VehiclePermissions MovementPermissions => SettingsCache.TryGetValue(VehicleDef, typeof(VehicleDef), nameof(VehicleDef.vehicleMovementPermissions), VehicleDef.vehicleMovementPermissions);
- public float WorldSpeedMultiplier => SettingsCache.TryGetValue(VehicleDef, typeof(VehicleProperties), nameof(VehicleProperties.worldSpeedMultiplier), VehicleDef.properties.worldSpeedMultiplier);
-
public bool CanMove => GetStatValue(VehicleStatDefOf.MoveSpeed) > 0.1f && MovementPermissions > VehiclePermissions.NotAllowed && movementStatus == VehicleMovementStatus.Online;
public bool CanMoveFinal => CanMove && (CanMoveWithOperators || VehicleMod.settings.debug.debugDraftAnyVehicle);
@@ -39,6 +37,16 @@ public partial class VehiclePawn
public CellRect Hitbox { get; private set; }
+ public float WorldSpeedMultiplier
+ {
+ get
+ {
+ float worldSpeedMultiplier = SettingsCache.TryGetValue(VehicleDef, typeof(VehicleProperties), nameof(VehicleProperties.worldSpeedMultiplier), VehicleDef.properties.worldSpeedMultiplier);
+ worldSpeedMultiplier = statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.WorldSpeedMultiplier, worldSpeedMultiplier);
+ return worldSpeedMultiplier;
+ }
+ }
+
public IEnumerable SurroundingCells
{
get
@@ -175,7 +183,7 @@ public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
}
}
- graphicInt = null;
+ ResetGraphic();
base.Destroy(mode);
}
diff --git a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Rendering.cs b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Rendering.cs
index f3e6f52f..b0d3c054 100644
--- a/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Rendering.cs
+++ b/Source/Vehicles/Components/Vehicles/VehiclePawn/VehiclePawn_Rendering.cs
@@ -12,7 +12,7 @@
using Verse.AI;
using Verse.AI.Group;
using SmashTools;
-using Mono.Security;
+using SmashTools.Animations;
namespace Vehicles
{
@@ -27,11 +27,12 @@ public partial class VehiclePawn
public VehicleGraphicOverlay graphicOverlay;
public PatternData patternData;
- public RetextureDef retexture;
+ private RetextureDef retextureDef;
private float angle = 0f; /* -45 is left, 45 is right : relative to Rot4 direction*/
- private Graphic_Vehicle graphicInt;
+ private Graphic_Vehicle graphic;
+
public PatternData patternToPaint;
private bool crashLanded;
@@ -50,6 +51,8 @@ public partial class VehiclePawn
public ThingWithComps Thing => this;
+ public ModContentPack ModContentPack => VehicleDef.modContentPack;
+
public bool CrashLanded
{
get
@@ -110,43 +113,11 @@ public Graphic_Vehicle VehicleGraphic
{
get
{
- if (graphicInt is null)
+ if (graphic is null)
{
- if (Destroyed && !RGBMaterialPool.GetAll(this).NullOrEmpty())
- {
- Log.Error($"Reinitializing RGB Materials but {this} has already been destroyed and the cache was not cleared for this entry. This may result in a memory leak.");
- RGBMaterialPool.Release(this);
- }
-
- GraphicDataRGB graphicData = new GraphicDataRGB();
- if (retexture != null)
- {
- graphicData.CopyFrom(retexture.graphicData);
- }
- else
- {
- graphicData.CopyFrom(VehicleDef.graphicData);
- }
- graphicData.color = patternData.color;
- graphicData.colorTwo = patternData.colorTwo;
- graphicData.colorThree = patternData.colorThree;
- graphicData.tiles = patternData.tiles;
- graphicData.displacement = patternData.displacement;
- graphicData.pattern = patternData.patternDef;
-
- if (graphicData.shaderType.Shader.SupportsRGBMaskTex())
- {
- RGBMaterialPool.CacheMaterialsFor(this);
- graphicData.Init(this);
- graphicInt = graphicData.Graphic as Graphic_Vehicle;
- RGBMaterialPool.SetProperties(this, patternData, graphicInt.TexAt, graphicInt.MaskAt);
- }
- else
- {
- graphicInt = ((GraphicData)graphicData).Graphic as Graphic_Vehicle; //Triggers vanilla Init call for normal material caching
- }
+ graphic = GenerateGraphic();
}
- return graphicInt;
+ return graphic;
}
}
@@ -341,6 +312,8 @@ public virtual void DrawAt(Vector3 drawLoc, Rot8 rot, float extraRotation, bool
bool northSouthRotation = VehicleGraphic.EastDiagonalRotated && (FullRotation == Rot8.NorthEast || FullRotation == Rot8.SouthEast) ||
(VehicleGraphic.WestDiagonalRotated && (FullRotation == Rot8.NorthWest || FullRotation == Rot8.SouthWest));
Drawer.renderer.RenderPawnAt(drawLoc, extraRotation, northSouthRotation);
+
+ //TODO - consolidate rendering to VehicleRenderer
foreach (VehicleHandler handler in HandlersWithPawnRenderer)
{
handler.RenderPawns();
@@ -392,7 +365,7 @@ public virtual void DrawExplosiveWicks(Vector3 drawLoc, Rot8 rot)
public void ResetRenderStatus()
{
- HandlersWithPawnRenderer = handlers.Where(h => h.role.pawnRenderer != null).ToList();
+ HandlersWithPawnRenderer = handlers.Where(h => h.role.PawnRenderer != null).ToList();
}
public override void Notify_ColorChanged()
@@ -403,6 +376,12 @@ public override void Notify_ColorChanged()
base.Notify_ColorChanged();
}
+ public void ResetGraphic()
+ {
+ graphic = null;
+ }
+
+ //TODO 1.6 - Make private and rename to ResetMaterialProperties
internal void ResetGraphicCache()
{
if (UnityData.IsInMainThread)
@@ -418,6 +397,46 @@ internal void ResetGraphicCache()
}
}
+ private Graphic_Vehicle GenerateGraphic()
+ {
+ if (Destroyed && !RGBMaterialPool.GetAll(this).NullOrEmpty())
+ {
+ Log.Error($"Reinitializing RGB Materials but {this} has already been destroyed and the cache was not cleared for this entry. This may result in a memory leak.");
+ RGBMaterialPool.Release(this);
+ }
+
+ Graphic_Vehicle newGraphic;
+ GraphicDataRGB graphicData = new GraphicDataRGB();
+ if (retextureDef != null)
+ {
+ graphicData.CopyFrom(retextureDef.graphicData);
+ }
+ else
+ {
+ graphicData.CopyFrom(VehicleDef.graphicData);
+ }
+ graphicData.color = patternData.color;
+ graphicData.colorTwo = patternData.colorTwo;
+ graphicData.colorThree = patternData.colorThree;
+ graphicData.tiles = patternData.tiles;
+ graphicData.displacement = patternData.displacement;
+ graphicData.pattern = patternData.patternDef;
+
+ if (graphicData.shaderType.Shader.SupportsRGBMaskTex())
+ {
+ RGBMaterialPool.CacheMaterialsFor(this);
+ GraphicDatabaseRGB.Remove(this); //Clear cached graphic to pick up potential retexture changes
+ graphicData.Init(this);
+ newGraphic = graphicData.Graphic as Graphic_Vehicle;
+ RGBMaterialPool.SetProperties(this, patternData, newGraphic.TexAt, newGraphic.MaskAt);
+ }
+ else
+ {
+ newGraphic = ((GraphicData)graphicData).Graphic as Graphic_Vehicle; //Triggers vanilla Init call for normal material caching
+ }
+ return newGraphic;
+ }
+
public void UpdateRotationAndAngle()
{
UpdateRotation();
@@ -537,6 +556,8 @@ public override IEnumerable GetGizmos()
}
}
+ bool upgrading = CompUpgradeTree != null && CompUpgradeTree.Upgrading;
+
if (!cargoToLoad.NullOrEmpty())
{
Command_Action cancelLoad = new Command_Action
@@ -562,6 +583,10 @@ public override IEnumerable GetGizmos()
Find.WindowStack.Add(new Dialog_LoadCargo(this));
}
};
+ if (upgrading)
+ {
+ loadVehicle.Disable("VF_DisabledByVehicleUpgrading".Translate(LabelCap));
+ }
yield return loadVehicle;
}
@@ -615,7 +640,7 @@ public override IEnumerable GetGizmos()
{
if (target.Thing is Pawn pawn && pawn.IsColonistPlayerControlled && !pawn.Downed)
{
- VehicleHandler handler = pawn.IsColonistPlayerControlled ? NextAvailableHandler() : handlers.FirstOrDefault(handler => handler.AreSlotsAvailable && handler.role.handlingTypes == HandlingTypeFlags.None);
+ VehicleHandler handler = pawn.IsColonistPlayerControlled ? NextAvailableHandler() : handlers.FirstOrDefault(handler => handler.AreSlotsAvailable && handler.role.HandlingTypes == HandlingTypeFlags.None);
PromptToBoardVehicle(pawn, handler);
return;
}
@@ -629,6 +654,10 @@ public override IEnumerable GetGizmos()
}, this);
}
};
+ if (upgrading)
+ {
+ flagForLoading.Disable("VF_DisabledByVehicleUpgrading".Translate(LabelCap));
+ }
yield return flagForLoading;
if (!Drafted)
@@ -874,7 +903,10 @@ public override IEnumerable GetFloatMenuOptions(Pawn selPawn)
{
yield break;
}
-
+ if (selPawn.Faction != Faction)
+ {
+ yield break;
+ }
if (!selPawn.RaceProps.ToolUser)
{
yield break;
@@ -907,7 +939,7 @@ public override IEnumerable GetFloatMenuOptions(Pawn selPawn)
if (handler.AreSlotsAvailable)
{
VehicleReservationManager reservationManager = Map.GetCachedMapComponent();
- FloatMenuOption opt = new FloatMenuOption("VF_EnterVehicle".Translate(LabelShort, handler.role.label, (handler.role.slots - (handler.handlers.Count +
+ FloatMenuOption opt = new FloatMenuOption("VF_EnterVehicle".Translate(LabelShort, handler.role.label, (handler.role.Slots - (handler.handlers.Count +
reservationManager.GetReservation(this)?.ClaimantsOnHandler(handler) ?? 0)).ToString()), delegate ()
{
PromptToBoardVehicle(selPawn, handler);
@@ -985,6 +1017,18 @@ public void ChangeColor()
});
}
+ public void SetRetexture(RetextureDef retextureDef)
+ {
+ SetRetextureInternal(this, retextureDef);
+ }
+
+ private static void SetRetextureInternal(VehiclePawn vehicle, RetextureDef retextureDef)
+ {
+ vehicle.retextureDef = retextureDef;
+ vehicle.ResetGraphic();
+ vehicle.Notify_ColorChanged();
+ }
+
public void Rename()
{
if (Nameable)
@@ -1070,6 +1114,12 @@ public virtual float DoInspectPaneButtons(float x)
{
options.Add(new FloatMenuOption("Open in animator", OpenInAnimator));
}
+#if DEBUG
+ if (CompVehicleLauncher != null)
+ {
+ options.Add(new FloatMenuOption("Open in animator (test version)", OpenInAnimator_New));
+ }
+#endif
if (!options.NullOrEmpty())
{
Find.WindowStack.Add(new FloatMenu(options));
@@ -1091,6 +1141,12 @@ public void OpenInAnimator()
Find.WindowStack.Add(dialog_GraphEditor);
}
+ public void OpenInAnimator_New()
+ {
+ Dialog_AnimationEditor dialog_GraphEditor = new Dialog_AnimationEditor(this);
+ Find.WindowStack.Add(dialog_GraphEditor);
+ }
+
public void MultiplePawnFloatMenuOptions(List pawns)
{
List options = new List();
@@ -1112,7 +1168,7 @@ public void MultiplePawnFloatMenuOptions(List pawns)
{
continue;
}
- VehicleHandler handler = p.IsColonistPlayerControlled ? NextAvailableHandler() : handlers.FirstOrDefault(handler => handler.AreSlotsAvailable && handler.role.handlingTypes == HandlingTypeFlags.None);
+ VehicleHandler handler = p.IsColonistPlayerControlled ? NextAvailableHandler() : handlers.FirstOrDefault(handler => handler.AreSlotsAvailable && handler.role.HandlingTypes == HandlingTypeFlags.None);
PromptToBoardVehicle(p, handler);
}
}, MenuOptionPriority.Default, null, null, 0f, null, null);
diff --git a/Source/Vehicles/Components/Vehicles/VehicleProperties.cs b/Source/Vehicles/Components/Vehicles/VehicleProperties.cs
index 27c66fcd..575f640b 100644
--- a/Source/Vehicles/Components/Vehicles/VehicleProperties.cs
+++ b/Source/Vehicles/Components/Vehicles/VehicleProperties.cs
@@ -11,8 +11,10 @@ namespace Vehicles
[HeaderTitle(Label = "VF_Properties", Translate = true)]
public class VehicleProperties
{
+#if !FISHING_DISABLED
[PostToSettings(Label = "VF_FishingEnabled", Tooltip = "VF_FishingEnabledTooltip", Translate = true, UISettingsType = UISettingsType.Checkbox, VehicleType = VehicleType.Sea)]
[DisableSettingConditional(MayRequireAny = new string[] { CompatibilityPackageIds.VE_Fishing })]
+#endif
public bool fishing = false;
public VehicleTrack track;
@@ -55,8 +57,12 @@ public class VehicleProperties
public SimpleDictionary customThingCosts;
// World Pathing
+ [PostToSettings(Label = "VF_OffRoadMultiplier", Tooltip = "VF_OffRoadMultiplierTooltip", Translate = true, UISettingsType = UISettingsType.SliderFloat)]
+ [SliderValues(MinValue = 0.01f, MaxValue = 2, RoundDecimalPlaces = 1)]
public float offRoadMultiplier = 1;
+
public float riverCost = -1;
+
public SimpleDictionary customRiverCosts = new SimpleDictionary();
public SimpleDictionary customBiomeCosts = new SimpleDictionary();
public SimpleDictionary customHillinessCosts = new SimpleDictionary();
@@ -66,8 +72,10 @@ public class VehicleProperties
[PostToSettings(Label = "VF_WinterSpeedMultiplier", Tooltip = "VF_WinterSpeedMultiplierTooltip", Translate = true, UISettingsType = UISettingsType.SliderFloat)]
[SliderValues(MinValue = 0, MaxValue = 10, RoundDecimalPlaces = 1)]
- [LoadAlias("winterSpeedMultiplier")] //Changed in 1.5.1381
- public float winterCostMultiplier = 2.5f;
+ [LoadAlias("winterSpeedMultiplier")] //Changed in 1.5.1381 1.6 - Remove LoadAlias
+ [LoadAlias("winterCostMultiplier")] //Changed in 1.5.1644 1.6 - Remove LoadAlias, Change UpgradeStatDef to match this name
+ public float winterCost = 2f;
+
[PostToSettings(Label = "VF_WorldSpeedMultiplier", Tooltip = "VF_WorldSpeedMultiplierTooltip", Translate = true, UISettingsType = UISettingsType.SliderFloat)]
[SliderValues(MinValue = 0, MaxValue = 10, RoundDecimalPlaces = 1)]
public float worldSpeedMultiplier = 2.5f;
diff --git a/Source/Vehicles/Components/Vehicles/VehicleRole.cs b/Source/Vehicles/Components/Vehicles/VehicleRole.cs
index b3c47f58..8cb16704 100644
--- a/Source/Vehicles/Components/Vehicles/VehicleRole.cs
+++ b/Source/Vehicles/Components/Vehicles/VehicleRole.cs
@@ -1,26 +1,35 @@
using System.Collections.Generic;
using Verse;
using SmashTools;
+using static Vehicles.VehicleUpgrade;
namespace Vehicles
{
+ ///
+ /// Container of data related to a 'seat' in a vehicle
+ ///
public class VehicleRole : ITweakFields
{
public string key;
public string label = "[MissingLabel]";
//Operating
- public HandlingTypeFlags handlingTypes = HandlingTypeFlags.None;
- public int slots;
- public int slotsToOperate;
- public List turretIds;
+ private HandlingTypeFlags handlingTypes = HandlingTypeFlags.None;
+ private int slots;
+ private int slotsToOperate;
+ private float comfort = 0.5f;
+ private List turretIds;
+
//Damaging
- public ComponentHitbox hitbox = new ComponentHitbox();
- public bool exposed = false;
- public float chanceToHit = 0.3f;
+ private ComponentHitbox hitbox = new ComponentHitbox();
+ private bool exposed = false;
+ private float chanceToHit = 0.3f;
+
//Rendering
[TweakField]
- public PawnOverlayRenderer pawnRenderer;
+ private PawnOverlayRenderer pawnRenderer;
+
+ private readonly List upgrades = new List();
public VehicleRole()
{
@@ -36,28 +45,268 @@ public VehicleRole(VehicleRole reference)
{
Log.Error($"Missing Key on VehicleRole {reference.label}");
}
+ CopyFrom(reference);
+ }
+
+ //Operating
+ public HandlingTypeFlags HandlingTypes
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.handlingTypes != null)
+ {
+ return roleUpgrade.handlingTypes.Value;
+ }
+ }
+ }
+ return handlingTypes;
+ }
+ }
+
+ public int Slots
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.slots != null)
+ {
+ return roleUpgrade.slots.Value;
+ }
+ }
+ }
+ return slots;
+ }
+ }
+
+ public int SlotsToOperate
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ foreach (RoleUpgrade roleUpgrade in upgrades)
+ {
+ if (roleUpgrade.slotsToOperate != null)
+ {
+ return roleUpgrade.slotsToOperate.Value;
+ }
+ }
+ }
+ return slotsToOperate;
+ }
+ }
+
+ public float Comfort
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ foreach (RoleUpgrade roleUpgrade in upgrades)
+ {
+ if (roleUpgrade.comfort != null)
+ {
+ return roleUpgrade.comfort.Value;
+ }
+ }
+ }
+ return comfort;
+ }
+ }
+
+ public List TurretIds
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.turretIds != null) //empty turret ids can be used to override role management of turret
+ {
+ return roleUpgrade.turretIds;
+ }
+ }
+ }
+ return turretIds;
+ }
+ }
+
+ //Damaging
+ public ComponentHitbox Hitbox
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.hitbox != null) //empty turret ids can be used to override role management of turret
+ {
+ return roleUpgrade.hitbox;
+ }
+ }
+ }
+ return hitbox;
+ }
+ }
+
+ public bool Exposed
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.exposed != null)
+ {
+ return roleUpgrade.exposed.Value;
+ }
+ }
+ }
+ return exposed;
+ }
+ }
+
+ public float ChanceToHit
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.chanceToHit != null)
+ {
+ return roleUpgrade.chanceToHit.Value;
+ }
+ }
+ }
+ return chanceToHit;
+ }
+ }
+
+ //Rendering
+ public PawnOverlayRenderer PawnRenderer
+ {
+ get
+ {
+ if (!upgrades.NullOrEmpty())
+ {
+ for (int i = upgrades.Count - 1; i >= 0; i--)
+ {
+ RoleUpgrade roleUpgrade = upgrades[i];
+ if (roleUpgrade.pawnRenderer != null)
+ {
+ return roleUpgrade.pawnRenderer;
+ }
+ }
+ }
+ return pawnRenderer;
+ }
+ }
+
+ public bool RequiredForCaravan => slotsToOperate > 0 && handlingTypes.HasFlag(HandlingTypeFlags.Movement);
+
+ string ITweakFields.Category => nameof(PawnOverlayRenderer);
+
+ string ITweakFields.Label => label;
+
+ public bool Resolved { get; private set; } = false;
+
+ public void AddUpgrade(RoleUpgrade roleUpgrade)
+ {
+ upgrades.Add(roleUpgrade);
+ }
+
+ public void RemoveUpgrade(RoleUpgrade roleUpgrade)
+ {
+ upgrades.Remove(roleUpgrade);
+ }
+
+ public void CopyFrom(VehicleRole reference)
+ {
key = reference.key;
label = reference.label;
+
handlingTypes = reference.handlingTypes;
slots = reference.slots;
slotsToOperate = reference.slotsToOperate;
+
+ turretIds = null;
if (!reference.turretIds.NullOrEmpty())
{
turretIds = new List(reference.turretIds);
}
+
hitbox = reference.hitbox;
+ exposed = reference.exposed;
+ chanceToHit = reference.chanceToHit;
+
pawnRenderer = reference.pawnRenderer;
}
- public bool RequiredForCaravan => slotsToOperate > 0 && handlingTypes.HasFlag(HandlingTypeFlags.Movement);
-
- string ITweakFields.Category => nameof(PawnOverlayRenderer);
+ public void CopyFrom(RoleUpgrade upgrade)
+ {
+ if (upgrade.handlingTypes != null)
+ {
+ handlingTypes = upgrade.handlingTypes.Value;
+ }
+ if (upgrade.slots != null)
+ {
+ slots = upgrade.slots.Value;
+ }
+ if (upgrade.slotsToOperate != null)
+ {
+ slotsToOperate = upgrade.slotsToOperate.Value;
+ }
+ if (upgrade.turretIds != null)
+ {
+ turretIds = new List(upgrade.turretIds);
+ }
+ if (upgrade.hitbox != null)
+ {
+ hitbox = upgrade.hitbox;
+ }
+ if (upgrade.exposed != null)
+ {
+ exposed = upgrade.exposed.Value;
+ }
+ if (upgrade.chanceToHit != null)
+ {
+ chanceToHit = upgrade.chanceToHit.Value;
+ }
- string ITweakFields.Label => label;
+ if (pawnRenderer != null)
+ {
+ pawnRenderer = upgrade.pawnRenderer;
+ }
+ }
public void ResolveReferences(VehicleDef vehicleDef)
{
+ if (Resolved)
+ {
+ return;
+ }
+
hitbox.Initialize(vehicleDef);
+
+ Resolved = true;
}
void ITweakFields.OnFieldChanged()
diff --git a/Source/Vehicles/Comps/Cannons/CompProperties_VehicleTurrets.cs b/Source/Vehicles/Comps/Cannons/CompProperties_VehicleTurrets.cs
index 038806c5..88242170 100644
--- a/Source/Vehicles/Comps/Cannons/CompProperties_VehicleTurrets.cs
+++ b/Source/Vehicles/Comps/Cannons/CompProperties_VehicleTurrets.cs
@@ -5,10 +5,11 @@
namespace Vehicles
{
+ [HeaderTitle(Label = "VF_TurretProperties", Translate = true)]
public class CompProperties_VehicleTurrets : VehicleCompProperties
{
//deploy time in seconds
- [PostToSettings(Label = "VF_DeployTime", Translate = true, UISettingsType = UISettingsType.FloatBox)]
+ //[PostToSettings(Label = "VF_DeployTime", Translate = true, UISettingsType = UISettingsType.FloatBox)]
[NumericBoxValues(MinValue = 0)]
[ActionOnSettingsInput(typeof(CompProperties_VehicleTurrets), nameof(CompProperties_VehicleTurrets.RecacheAllTurrets))]
public float deployTime = 0;
diff --git a/Source/Vehicles/Comps/Cannons/CompVehicleTurrets.cs b/Source/Vehicles/Comps/Cannons/CompVehicleTurrets.cs
index 15f4274f..a12e8797 100644
--- a/Source/Vehicles/Comps/Cannons/CompVehicleTurrets.cs
+++ b/Source/Vehicles/Comps/Cannons/CompVehicleTurrets.cs
@@ -19,14 +19,15 @@ public class CompVehicleTurrets : VehicleAIComp, IRefundable
internal int deployTicks;
private Dictionary turretQuotas = new Dictionary();
+ private List backupQuotas = new List();
[TweakField]
public List turrets = new List();
private List tickers = new List();
- private static List tmpListTurrets = new List();
- private static List tmpListTurretQuota = new List();
+ private List tmpListTurrets = new List();
+ private List tmpListTurretQuota = new List();
public bool CanDeploy { get; private set; }
@@ -84,11 +85,18 @@ public void FlagAllTurretsForAlignment()
{
foreach (VehicleTurret turret in turrets)
{
- if (turret.TurretRotation != turret.defaultAngleRotated)
+ if (turret.deployment != DeploymentType.None)
{
- turret.SetTarget(LocalTargetInfo.Invalid);
- turret.FlagForAlignment();
- turret.StartTicking();
+ if (TurretTargeter.Turret == turret)
+ {
+ TurretTargeter.Instance.StopTargeting(true);
+ }
+ if (turret.TurretRotation != turret.defaultAngleRotated)
+ {
+ turret.SetTarget(LocalTargetInfo.Invalid);
+ turret.FlagForAlignment();
+ turret.StartTicking();
+ }
}
}
}
@@ -144,12 +152,56 @@ public bool GetTurretToFill(out VehicleTurret turretToFill, out int quota)
return false;
}
- public void AddTurret(VehicleTurret turret)
+ public VehicleTurret GetTurret(string key)
+ {
+ foreach (VehicleTurret turret in turrets)
+ {
+ if (turret.key == key)
+ {
+ return turret;
+ }
+ }
+ return null;
+ }
+
+ public void AddTurret(VehicleTurret turret, string upgradeKey = null)
{
- VehicleTurret newTurret = CreateTurret(Vehicle, turret);
+ VehicleTurret newTurret = CreateTurret(Vehicle, turret, upgradeKey: upgradeKey);
newTurret.FillEvents_Def();
turrets.Add(newTurret);
RevalidateTurrets();
+
+ if (!backupQuotas.NullOrEmpty())
+ {
+ for (int i = 0; i < backupQuotas.Count; i++)
+ {
+ BackupTurretQuota quota = backupQuotas[i];
+ if (quota.key == newTurret.key && quota.upgradeKey == newTurret.upgradeKey)
+ {
+ SetQuotaLevel(newTurret, quota.config);
+ backupQuotas.RemoveAt(i);
+ break;
+ }
+ }
+ }
+
+ if (Vehicle.CompUpgradeTree != null && Vehicle.CompUpgradeTree.TryGetStates(turret.key, out List states))
+ {
+ //Re-unlock turret-type settings to ensure proper values are initialized for new turrets of existing keys
+ foreach (UpgradeState state in states)
+ {
+ if (!state.settings.NullOrEmpty())
+ {
+ foreach (UpgradeState.Setting setting in state.settings)
+ {
+ if (setting is UpgradeSetting_Turret turretSetting && turretSetting.turretKey == turret.key)
+ {
+ turretSetting.Unlocked(Vehicle, false);
+ }
+ }
+ }
+ }
+ }
}
public bool RemoveTurret(string key)
@@ -167,6 +219,19 @@ public bool RemoveTurret(string key)
public bool RemoveTurret(VehicleTurret turret)
{
+ turret.TryRemoveShell();
+ if (turretQuotas.TryGetValue(turret, out int quota))
+ {
+ //Move turret quota to simple list for storage, may pull config later if turret is re-added
+ backupQuotas.Add(new BackupTurretQuota()
+ {
+ key = turret.key,
+ upgradeKey = turret.upgradeKey,
+ config = quota,
+ });
+ turretQuotas.Remove(turret);
+ }
+ turret.OnDestroy();
return turrets.Remove(turret);
}
@@ -206,6 +271,9 @@ public override IEnumerable CompGetGizmosExtra()
{
yield break; //Don't return any gizmos if belonging to another faction
}
+
+ bool upgrading = Vehicle.CompUpgradeTree != null && Vehicle.CompUpgradeTree.Upgrading;
+
if (CanDeploy)
{
Command_Toggle deployToggle = new Command_Toggle
@@ -217,6 +285,7 @@ public override IEnumerable CompGetGizmosExtra()
{
Vehicle.jobs.StartJob(new Job(JobDefOf_Vehicles.DeployVehicle, targetA: Vehicle), JobCondition.InterruptForced);
deployTicks = DeployTicks;
+
},
isActive = () => Deployed
};
@@ -232,6 +301,10 @@ public override IEnumerable CompGetGizmosExtra()
{
deployToggle.Disable();
}
+ if (upgrading)
+ {
+ deployToggle.Disable("VF_DisabledByVehicleUpgrading".Translate(Vehicle.LabelCap));
+ }
yield return deployToggle;
}
if (turrets.Count > 0)
@@ -265,7 +338,7 @@ public override IEnumerable CompGetGizmosExtra()
turretNumber++;
foreach (VehicleHandler relatedHandler in Vehicle.GetAllHandlersMatch(HandlingTypeFlags.Turret, turret.key))
{
- if (relatedHandler.handlers.Count < relatedHandler.role.slotsToOperate && !VehicleMod.settings.debug.debugShootAnyTurret)
+ if (relatedHandler.handlers.Count < relatedHandler.role.SlotsToOperate && !VehicleMod.settings.debug.debugShootAnyTurret)
{
turretTargeterGizmo.Disable("VF_NotEnoughCrew".Translate(Vehicle.LabelShort, relatedHandler.role.label));
break;
@@ -283,6 +356,10 @@ public override IEnumerable CompGetGizmosExtra()
{
turretTargeterGizmo.Disable("VF_TurretComponentDisabled".Translate(turret.component.Label));
}
+ if (upgrading)
+ {
+ turretTargeterGizmo.Disable("VF_DisabledByVehicleUpgrading".Translate(Vehicle.LabelCap));
+ }
yield return turretTargeterGizmo;
}
if (DebugSettings.ShowDevGizmos)
@@ -325,7 +402,7 @@ public override IEnumerable CompGetGizmosExtra()
foreach (VehicleHandler relatedHandler in Vehicle.GetAllHandlersMatch(HandlingTypeFlags.Turret, turret.key))
{
- if (relatedHandler.handlers.Count < relatedHandler.role.slotsToOperate && !VehicleMod.settings.debug.debugShootAnyTurret)
+ if (relatedHandler.handlers.Count < relatedHandler.role.SlotsToOperate && !VehicleMod.settings.debug.debugShootAnyTurret)
{
turretCommand.Disable("VF_NotEnoughCrew".Translate(Vehicle.LabelShort, relatedHandler.role.label));
break;
@@ -341,6 +418,10 @@ public override IEnumerable CompGetGizmosExtra()
}
if (newCommand)
{
+ if (upgrading)
+ {
+ turretCommand.Disable("VF_DisabledByVehicleUpgrading".Translate(Vehicle.LabelCap));
+ }
yield return turretCommand;
if (!turret.groupKey.NullOrEmpty())
{
@@ -568,10 +649,12 @@ public void ToggleDeployment()
if (deployed)
{
Props.deploySound?.PlayOneShot(Vehicle);
+ Vehicle.EventRegistry[VehicleEventDefOf.Deployed].ExecuteEvents();
}
else
{
Props.undeploySound?.PlayOneShot(Vehicle);
+ Vehicle.EventRegistry[VehicleEventDefOf.Undeployed].ExecuteEvents();
}
}
@@ -616,11 +699,12 @@ public override void EventRegistration()
}
}
- public static VehicleTurret CreateTurret(VehiclePawn vehicle, VehicleTurret reference)
+ public static VehicleTurret CreateTurret(VehiclePawn vehicle, VehicleTurret reference, string upgradeKey = null)
{
VehicleTurret newTurret = (VehicleTurret)Activator.CreateInstance(reference.GetType(), new object[] { vehicle, reference });
newTurret.SetTarget(LocalTargetInfo.Invalid);
newTurret.ResetAngle();
+ newTurret.upgradeKey = upgradeKey;
return newTurret;
}
@@ -657,6 +741,7 @@ public void RevalidateTurrets()
turretQueue ??= new List();
ResolveChildTurrets();
RecacheDeployment();
+ RecacheTurretPermissions();
InitTurrets();
}
@@ -697,7 +782,7 @@ public void InitTurrets()
for (int i = turrets.Count - 1; i >= 0; i--)
{
VehicleTurret turret = turrets[i];
- VehicleTurret reference = FindTurretReference(turret.key);
+ VehicleTurret reference = FindTurretReference(turret);
if (reference != null)
{
@@ -711,14 +796,34 @@ public void InitTurrets()
}
}
- private VehicleTurret FindTurretReference(string key)
+ private VehicleTurret FindTurretReference(VehicleTurret turret)
{
- if (MatchingTurret(key, Props.turrets, out VehicleTurret result))
+ if (!turret.upgradeKey.NullOrEmpty() && Vehicle.CompUpgradeTree != null)
+ {
+ foreach (UpgradeNode upgradeNode in Vehicle.CompUpgradeTree.Props.def.nodes)
+ {
+ if (!upgradeNode.upgrades.NullOrEmpty())
+ {
+ foreach (Upgrade upgrade in upgradeNode.upgrades)
+ {
+ if (upgrade is TurretUpgrade turretUpgrade)
+ {
+ if (MatchingTurret(turret.key, turretUpgrade.turrets, out VehicleTurret upgradeResult))
+ {
+ return upgradeResult;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (MatchingTurret(turret.key, Props.turrets, out VehicleTurret result))
{
return result;
}
else if (Vehicle.CompUpgradeTree != null)
{
+ Log.Warning($"Unable to locate {turret.key} in CompProperties with null upgradeKey. Sweeping UpgradeTree for any matching turret.");
foreach (UpgradeNode upgradeNode in Vehicle.CompUpgradeTree.Props.def.nodes)
{
if (!upgradeNode.upgrades.NullOrEmpty())
@@ -727,7 +832,7 @@ private VehicleTurret FindTurretReference(string key)
{
if (upgrade is TurretUpgrade turretUpgrade)
{
- if (MatchingTurret(key, turretUpgrade.turrets, out VehicleTurret upgradeResult))
+ if (MatchingTurret(turret.key, turretUpgrade.turrets, out VehicleTurret upgradeResult))
{
return upgradeResult;
}
@@ -835,8 +940,10 @@ public override void PostExposeData()
Scribe_Collections.Look(ref turrets, nameof(turrets), LookMode.Deep, ctorArgs: Vehicle);
Scribe_Collections.Look(ref turretQueue, nameof(turretQueue), LookMode.Reference);
Scribe_Collections.Look(ref turretQuotas, nameof(turretQuotas), LookMode.Reference, LookMode.Value, ref tmpListTurrets, ref tmpListTurretQuota);
+ Scribe_Collections.Look(ref backupQuotas, nameof(backupQuotas), LookMode.Deep);
turretQuotas ??= new Dictionary();
+ backupQuotas ??= new List();
}
public struct TurretData : IExposable
@@ -859,5 +966,22 @@ public void ExposeData()
Scribe_References.Look(ref turret, nameof(turret));
}
}
+
+ ///
+ /// Used for serializing turret quotas of turrets that were removed, such that they will reload the quota if re-added
+ ///
+ public struct BackupTurretQuota : IExposable
+ {
+ public string key;
+ public string upgradeKey;
+ public int config;
+
+ public void ExposeData()
+ {
+ Scribe_Values.Look(ref key, nameof(key));
+ Scribe_Values.Look(ref upgradeKey, nameof(upgradeKey));
+ Scribe_Values.Look(ref config, nameof(config));
+ }
+ }
}
}
diff --git a/Source/Vehicles/Comps/FueledTravel/CompFueledTravel.cs b/Source/Vehicles/Comps/FueledTravel/CompFueledTravel.cs
index 235e8a27..7f95bd42 100644
--- a/Source/Vehicles/Comps/FueledTravel/CompFueledTravel.cs
+++ b/Source/Vehicles/Comps/FueledTravel/CompFueledTravel.cs
@@ -39,10 +39,6 @@ public class CompFueledTravel : VehicleComp, IRefundable
private CompPower connectedPower;
private bool postLoadReconnect;
- public float dischargeRate;
-
- private float fuelConsumptionRateOffset;
- private float fuelCapacityOffset;
public List<(VehicleComponent component, Reactor_FuelLeak fuelLeak)> FuelComponents { get; private set; }
@@ -93,36 +89,43 @@ public static MethodInfo PowerNetMethod
}
}
- public virtual float FuelEfficiency
+ public virtual float ChargeRate
{
get
{
- return SettingsCache.TryGetValue(Vehicle.VehicleDef, typeof(CompProperties_FueledTravel), nameof(CompProperties_FueledTravel.fuelConsumptionRate), Props.fuelConsumptionRate) + fuelConsumptionRateOffset;
+ float chargeRate = Props.chargeRate;
+ chargeRate = Vehicle.statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.ChargeRate, chargeRate);
+ return chargeRate;
}
- set
+ }
+
+ public virtual float DischargeRate
+ {
+ get
{
- fuelConsumptionRateOffset = value;
+ float dischargeRate = Props.dischargeRate;// SettingsCache.TryGetValue(Vehicle.VehicleDef, typeof(CompProperties_FueledTravel), nameof(CompProperties_FueledTravel.dischargeRate), Props.dischargeRate);
+ dischargeRate = Vehicle.statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.DischargeRate, dischargeRate);
+ return dischargeRate;
}
}
- public virtual float FuelCapacity
+ public virtual float FuelEfficiency
{
get
{
- return SettingsCache.TryGetValue(Vehicle.VehicleDef, typeof(CompProperties_FueledTravel), nameof(CompProperties_FueledTravel.fuelCapacity), Props.fuelCapacity) + fuelCapacityOffset;
+ float consumptionRate = SettingsCache.TryGetValue(Vehicle.VehicleDef, typeof(CompProperties_FueledTravel), nameof(CompProperties_FueledTravel.fuelConsumptionRate), Props.fuelConsumptionRate);
+ consumptionRate = Vehicle.statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.FuelConsumptionRate, consumptionRate);
+ return consumptionRate;
}
- set
- {
- fuelCapacityOffset = value;
- if (fuelCapacityOffset < 0)
- {
- fuelCapacityOffset = 0f;
- }
+ }
- if (fuel > fuelCapacityOffset)
- {
- fuel = fuelCapacityOffset;
- }
+ public virtual float FuelCapacity
+ {
+ get
+ {
+ float fuelCapacity = SettingsCache.TryGetValue(Vehicle.VehicleDef, typeof(CompProperties_FueledTravel), nameof(CompProperties_FueledTravel.fuelCapacity), Props.fuelCapacity);
+ fuelCapacity = Vehicle.statHandler.GetStatOffset(VehicleStatUpgradeCategoryDefOf.FuelCapacity, fuelCapacity);
+ return fuelCapacity;
}
}
@@ -408,12 +411,12 @@ public override void CompTick()
{
if (!Charging)
{
- ConsumeFuel(Mathf.Min(Props.dischargeRate * EfficiencyTickMultiplier, Fuel));
+ ConsumeFuel(Mathf.Min(DischargeRate * EfficiencyTickMultiplier, Fuel));
}
else if(Find.TickManager.TicksGame % TicksToCharge == 0)
{
- PowerNetMethod.Invoke(connectedPower.PowerNet, new object[] { -Props.chargeRate });
- Refuel(Props.chargeRate);
+ PowerNetMethod.Invoke(connectedPower.PowerNet, new object[] { -ChargeRate });
+ Refuel(ChargeRate);
}
}
}
@@ -509,6 +512,7 @@ public virtual void DisconnectPower()
connectedPower = null;
}
+ //TODO - Refactor wind direction
public virtual void DrawMotes()
{
foreach (OffsetMote offset in Props.motesGenerated)
@@ -577,7 +581,6 @@ public override void PostSpawnSetup(bool respawningAfterLoad)
base.PostSpawnSetup(respawningAfterLoad);
if (!respawningAfterLoad)
{
- dischargeRate = ConsumptionRatePerTick * 0.1f;
targetFuelLevel = FuelCapacity;
}
@@ -593,14 +596,9 @@ public override void PostExposeData()
{
base.PostExposeData();
- //Upgrades
- Scribe_Values.Look(ref fuelConsumptionRateOffset, nameof(fuelConsumptionRateOffset));
- Scribe_Values.Look(ref fuelCapacityOffset, nameof(fuelCapacityOffset));
-
//CurValues
Scribe_Values.Look(ref fuel, nameof(fuel));
- Scribe_Values.Look(ref targetFuelLevel, nameof(targetFuelLevel), defaultValue: FuelCapacity);
- Scribe_Values.Look(ref dischargeRate, nameof(dischargeRate));
+ Scribe_Values.Look(ref targetFuelLevel, nameof(targetFuelLevel), defaultValue: Props.fuelCapacity);
if (Scribe.mode == LoadSaveMode.Saving)
{
diff --git a/Source/Vehicles/Comps/UpgradeTree/CompProperties_UpgradeTree.cs b/Source/Vehicles/Comps/UpgradeTree/CompProperties_UpgradeTree.cs
index 2ad6610d..7716816f 100644
--- a/Source/Vehicles/Comps/UpgradeTree/CompProperties_UpgradeTree.cs
+++ b/Source/Vehicles/Comps/UpgradeTree/CompProperties_UpgradeTree.cs
@@ -62,6 +62,7 @@ public override void ResolveReferences(ThingDef parentDef)
foreach (GraphicDataOverlay graphicDataOverlay in node.graphicOverlays)
{
GraphicOverlay graphicOverlay = GraphicOverlay.Create(graphicDataOverlay, vehicleDef);
+ graphicOverlay.data.graphicData.RecacheLayerOffsets();
overlays.AddOrInsert(node, graphicOverlay);
}
}
diff --git a/Source/Vehicles/Comps/UpgradeTree/CompUpgradeTree.cs b/Source/Vehicles/Comps/UpgradeTree/CompUpgradeTree.cs
index f18f3cae..82e818a1 100644
--- a/Source/Vehicles/Comps/UpgradeTree/CompUpgradeTree.cs
+++ b/Source/Vehicles/Comps/UpgradeTree/CompUpgradeTree.cs
@@ -27,6 +27,8 @@ public class CompUpgradeTree : VehicleComp
public ThingOwner upgradeContainer = new ThingOwner();
+ private Dictionary> states { get; set; } = new Dictionary>();
+
public CompProperties_UpgradeTree Props => (CompProperties_UpgradeTree)props;
public bool Upgrading => NodeUnlocking != null;
@@ -163,6 +165,7 @@ public void ResetUnlock(UpgradeNode node)
}
node.RemoveOverlays(Vehicle);
node.resetSound?.PlayOneShot(new TargetInfo(Vehicle.Position, Vehicle.Map));
+ Vehicle.EventRegistry[VehicleEventDefOf.VehicleUpgradeRefundCompleted].ExecuteEvents();
}
}
@@ -203,6 +206,8 @@ public void FinishUnlock(UpgradeNode node)
upgrades.Add(node.key);
upgradeContainer.ClearAndDestroyContents();
+
+ Vehicle.EventRegistry[VehicleEventDefOf.VehicleUpgradeCompleted].ExecuteEvents();
}
public void ClearUpgrade()
@@ -219,7 +224,7 @@ public void StartUnlock(UpgradeNode node)
{
upgrade = new UpgradeInProgress(Vehicle, node, false);
upgradeContainer.TryDropAll(Vehicle.Position, Vehicle.Map, ThingPlaceMode.Near);
- Vehicle.ignition.Drafted = false;
+ Vehicle.EventRegistry[VehicleEventDefOf.VehicleUpgradeEnqueued].ExecuteEvents();
}
///
@@ -229,7 +234,14 @@ public void RemoveUnlock(UpgradeNode node)
{
upgrade = new UpgradeInProgress(Vehicle, node, true);
upgradeContainer.TryDropAll(Vehicle.Position, Vehicle.Map, ThingPlaceMode.Near);
+ Vehicle.EventRegistry[VehicleEventDefOf.VehicleUpgradeRefundEnqueued].ExecuteEvents();
+ }
+
+ private void PrepVehicleForWork()
+ {
Vehicle.ignition.Drafted = false;
+ Vehicle.Angle = 0;
+ Vehicle.DisembarkAll();
}
private void ReloadUnlocks()
@@ -274,6 +286,30 @@ public void AddToContainer(ThingOwner holder, Thing thing, int count)
ValidateListers();
}
+ public void AddSettings(UpgradeState state)
+ {
+ if (!states.ContainsKey(state.key))
+ {
+ states[state.key] = new List();
+ }
+ states[state.key].Add(state);
+ }
+
+ public bool TryGetStates(string key, out List outList)
+ {
+ return states.TryGetValue(key, out outList);
+ }
+
+ public void RemoveSettings(UpgradeState state)
+ {
+ if (!states.TryGetValue(state.key, out List innerList))
+ {
+ Log.Error($"Unable to locate {state.key} in state cache.");
+ return;
+ }
+ innerList.Remove(state);
+ }
+
public override void PostDraw()
{
base.PostDraw();
@@ -285,7 +321,7 @@ public override void PostDraw()
size.y *= 1.15f;
Vector3 s = new Vector3(size.x, 1f, size.y);
Matrix4x4 matrix = default;
- matrix.SetTRS(drawPos, Vehicle.FullRotation.AsQuat, s);
+ matrix.SetTRS(drawPos, Vehicle.Rotation.AsQuat, s);
Graphics.DrawMesh(MeshPool.plane10, matrix, UnderfieldMat, 0);
int corners = 4;
for (int i = 0; i < corners; i++)
@@ -339,7 +375,7 @@ public override bool CanDraft(out string failReason, out bool allowDevMode)
allowDevMode = false;
if (Upgrading)
{
- failReason = "VF_UpgradeInProgress".Translate(Vehicle);
+ failReason = "VF_DisabledByVehicleUpgrading".Translate(Vehicle.LabelCap);
return false;
}
return base.CanDraft(out failReason, out allowDevMode);
@@ -364,7 +400,10 @@ public override void PostSpawnSetup(bool respawningAfterLoad)
public override void CompTickRare()
{
base.CompTickRare();
- ValidateListers();
+ if (Vehicle.Spawned)
+ {
+ ValidateListers();
+ }
}
public void ValidateListers()
@@ -389,6 +428,13 @@ public void ValidateListers()
}
}
+ public override void EventRegistration()
+ {
+ base.EventRegistration();
+ Vehicle.AddEvent(VehicleEventDefOf.VehicleUpgradeEnqueued, PrepVehicleForWork);
+ Vehicle.AddEvent(VehicleEventDefOf.VehicleUpgradeRefundEnqueued, PrepVehicleForWork);
+ }
+
public override void PostExposeData()
{
base.PostExposeData();
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_AttackSettlement.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_AttackSettlement.cs
index cd8185c3..7596c365 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_AttackSettlement.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_AttackSettlement.cs
@@ -31,12 +31,13 @@ public override FloatMenuAcceptanceReport StillValid(int destinationTile)
return CanAttack(vehicle, settlement);
}
- protected override void MapLoaded(Map map)
+ protected override void MapLoaded(Map map, bool generatedMap)
{
+ base.MapLoaded(map, generatedMap);
TaggedString letterLabel = "LetterLabelCaravanEnteredEnemyBase".Translate();
TaggedString letterText = "LetterTransportPodsLandedInEnemyBase".Translate(map.Parent.Label).CapitalizeFirst();
SettlementUtility.AffectRelationsOnAttacked(settlement, ref letterText);
- if (!settlement.HasMap)
+ if (generatedMap)
{
Find.TickManager.Notify_GeneratedPotentiallyHostileMap();
PawnRelationUtility.Notify_PawnsSeenByPlayer_Letter(map.mapPawns.AllPawns, ref letterLabel, ref letterText, "LetterRelatedPawnsInMapWherePlayerLanded".Translate(Faction.OfPlayer.def.pawnsPlural), true, true);
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_LoadMap.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_LoadMap.cs
index 09affe65..82b73456 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_LoadMap.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_LoadMap.cs
@@ -31,6 +31,14 @@ public override bool Arrived(int tile)
{
LongEventHandler.QueueLongEvent(delegate ()
{
+ MapParent mapParent = Find.WorldObjects.MapParentAt(tile);
+ if (mapParent == null)
+ {
+ Log.Error($"Trying to arrive at map with null MapParent.");
+ return;
+ }
+ bool mapGenerated = !mapParent.HasMap;
+
Site site = Find.WorldObjects.WorldObjectAt(tile);
Map map;
if (site != null)
@@ -42,14 +50,24 @@ public override bool Arrived(int tile)
map = GetOrGenerateMapUtility.GetOrGenerateMap(tile, null);
}
string label = map.Parent.Label;
- MapLoaded(map);
+ if (mapGenerated)
+ {
+ GetOrGenerateMapUtility.UnfogMapFromEdge(map);
+ }
+ MapLoaded(map, mapGenerated);
ExecuteEvents();
arrivalModeDef.Worker.VehicleArrived(vehicle, launchProtocol, map);
}, "GeneratingMap", false, null, true);
return true;
}
+ [Obsolete("Use new overload instead. Will be removed in 1.6")]
protected virtual void MapLoaded(Map map)
+ {
+ MapLoaded(map, true);
+ }
+
+ protected virtual void MapLoaded(Map map, bool hasMap)
{
}
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_StrafeMap.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_StrafeMap.cs
index 38bf8fdc..4212e0d9 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_StrafeMap.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/AerialFloatMenuOptions/AerialVehicleArrivalAction_StrafeMap.cs
@@ -28,7 +28,8 @@ public override FloatMenuAcceptanceReport StillValid(int destinationTile)
}
return CanAttack(vehicle, parent);
}
-
+
+ //NOTE - Needs Unfogger called if map is generated
public override bool Arrived(int tile)
{
LongEventHandler.QueueLongEvent(delegate ()
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DefaultTakeoff.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DefaultTakeoff.cs
index f715acba..e1f5dfee 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DefaultTakeoff.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DefaultTakeoff.cs
@@ -73,7 +73,7 @@ protected override int AnimationEditorTick_Takeoff(int ticksPassed)
return 0;
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LandingProperties.rotationCurve.NullOrEmpty())
{
@@ -120,7 +120,7 @@ protected override (Vector3 drawPos, float rotation, ShadowData shadowData) Anim
return base.AnimateLanding(drawPos, rotation, shadowData);
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LaunchProperties.rotationCurve.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DirectionalTakeoff.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DirectionalTakeoff.cs
index e35ca60a..440450dd 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DirectionalTakeoff.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/DirectionalTakeoff.cs
@@ -67,7 +67,7 @@ public override bool FinishedAnimation(VehicleSkyfaller skyfaller)
return TicksPassed >= CurAnimationProperties.maxTicks;
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LandingProperties.rotationCurve.NullOrEmpty())
{
@@ -112,7 +112,7 @@ protected override (Vector3 drawPos, float rotation, ShadowData shadowData) Anim
return base.AnimateLanding(drawPos, rotation, shadowData);
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LaunchProperties.rotationCurve.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/LaunchProtocol.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/LaunchProtocol.cs
index cb64dad1..6dfa47b1 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/LaunchProtocol.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/LaunchProtocol.cs
@@ -188,9 +188,8 @@ public virtual Command_ActionHighlighter LaunchCommand
public (Vector3 drawPos, float rotation) Draw(Vector3 drawPos, float rotation)
{
-
(Vector3 drawPos, float rotation) result = (drawPos, rotation);
- ShadowData shadowData = ShadowData.CreateFrom(vehicle);
+ DynamicShadowData shadowData = DynamicShadowData.CreateFrom(vehicle);
switch (launchType)
{
case LaunchType.Landing:
@@ -253,7 +252,7 @@ private void DrawShadow(Vector3 pos, Rot4 rot, Material material, float width, f
///
///
- protected virtual (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected virtual (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
return (drawPos, rotation, shadowData);
}
@@ -263,7 +262,7 @@ protected virtual (Vector3 drawPos, float rotation, ShadowData shadowData) Anima
///
///
- protected virtual (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected virtual (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
return (drawPos, rotation, shadowData);
}
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/PropellerTakeoff.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/PropellerTakeoff.cs
index 2449ce31..e780b0d4 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/PropellerTakeoff.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/PropellerTakeoff.cs
@@ -122,7 +122,7 @@ protected override int AnimationEditorTick_Takeoff(int ticksPassed)
return base.AnimationEditorTick_Takeoff(remaining);
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LandingProperties_Propeller.rotationPropellerCurve.NullOrEmpty())
{
@@ -161,7 +161,7 @@ protected override (Vector3 drawPos, float rotation, ShadowData shadowData) Anim
return base.AnimateLanding(drawPos, rotation, shadowData);
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LaunchProperties_Propeller.rotationPropellerCurve.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/VTOLTakeoff.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/VTOLTakeoff.cs
index a27e20b7..981d4ee1 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/VTOLTakeoff.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/VTOLTakeoff.cs
@@ -61,7 +61,7 @@ protected override int AnimationEditorTick_Landing(int ticksPassed)
return remaining;
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateLanding(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LandingProperties_VTOL.rotationVerticalCurve.NullOrEmpty())
{
@@ -100,7 +100,7 @@ protected override (Vector3 drawPos, float rotation, ShadowData shadowData) Anim
return base.AnimateLanding(drawPos, rotation, shadowData);
}
- protected override (Vector3 drawPos, float rotation, ShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, ShadowData shadowData)
+ protected override (Vector3 drawPos, float rotation, DynamicShadowData shadowData) AnimateTakeoff(Vector3 drawPos, float rotation, DynamicShadowData shadowData)
{
if (!LaunchProperties_VTOL.rotationVerticalCurve.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/LandingTargeter.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/LandingTargeter.cs
index ee0d9077..9f008b3b 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/LandingTargeter.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/LandingTargeter.cs
@@ -128,8 +128,16 @@ public PositionState GetPosState(LocalTargetInfo localTargetInfo, bool drawRestr
CellRect occupiedRect = GenAdj.OccupiedRect(cell, landingRotation, vehicle.VehicleDef.Size);
foreach (IntVec3 occupiedCell in occupiedRect)
{
+ if (RoofPunchOverride(map, occupiedCell, out int stateInt))
+ {
+ return (PositionState)stateInt;
+ }
if (occupiedCell.GetRoof(map) is RoofDef roofDef)
{
+ if (roofDef.GetModExtension() is RoofDefPositionStateDefModExtension roofDefPosition)
+ {
+ return roofDefPosition.state;
+ }
if (roofDef.isThickRoof)
{
return PositionState.Invalid;
@@ -141,6 +149,15 @@ public PositionState GetPosState(LocalTargetInfo localTargetInfo, bool drawRestr
return PositionState.Valid;
}
+ ///
+ /// Hook for modders to patch with no VehicleFramework types. Returns the int value of at
+ ///
+ private bool RoofPunchOverride(Map map, IntVec3 cell, out int stateInt)
+ {
+ stateInt = 0;
+ return false;
+ }
+
public override void ProcessInputEvents()
{
HandleRotationShortcuts();
@@ -304,11 +321,11 @@ public override void PostInit()
Instance = this;
}
- public enum PositionState
+ public enum PositionState : int
{
- Invalid,
- Obstructed,
- Valid
+ Invalid = 0,
+ Obstructed = 1,
+ Valid = 2
}
}
}
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/TurretTargeter.cs b/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/TurretTargeter.cs
index 732acc8e..f5384d13 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/TurretTargeter.cs
+++ b/Source/Vehicles/CustomFeatures/AerialVehicles/Targeters/TurretTargeter.cs
@@ -20,6 +20,26 @@ public class TurretTargeter : BaseTargeter
public override bool IsTargeting => action != null;
+ public bool TargeterValid
+ {
+ get
+ {
+ if (vehicle is null || vehicle.Map != Find.CurrentMap || vehicle.Destroyed)
+ {
+ return false;
+ }
+ if (Turret is null || Turret.ComponentDisabled)
+ {
+ return false;
+ }
+ if (!Find.Selector.IsSelected(vehicle))
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+
public static void BeginTargeting(TargetingParameters targetParams, Action action, VehicleTurret turret, Action actionWhenFinished = null, Texture2D mouseAttachment = null)
{
Instance.action = action;
@@ -58,7 +78,11 @@ public void StopTargeting(bool canceled)
public override void ProcessInputEvents()
{
- ConfirmStillValid();
+ if (!TargeterValid)
+ {
+ StopTargeting(true);
+ return;
+ }
if (IsTargeting)
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
@@ -122,14 +146,6 @@ public override void TargeterUpdate()
}
}
- private void ConfirmStillValid()
- {
- if (vehicle is null || (vehicle.Map != Find.CurrentMap || vehicle.Destroyed || Turret.ComponentDisabled || !Find.Selector.IsSelected(vehicle)))
- {
- StopTargeting(true);
- }
- }
-
protected override LocalTargetInfo CurrentTargetUnderMouse()
{
if (!IsTargeting)
diff --git a/Source/Vehicles/CustomFeatures/Misc/DrawOffsets.cs b/Source/Vehicles/CustomFeatures/Misc/Rendering/DrawOffsets.cs
similarity index 100%
rename from Source/Vehicles/CustomFeatures/Misc/DrawOffsets.cs
rename to Source/Vehicles/CustomFeatures/Misc/Rendering/DrawOffsets.cs
diff --git a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/Misc/ShadowData.cs b/Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadowData.cs
similarity index 73%
rename from Source/Vehicles/CustomFeatures/AerialVehicles/Launching/Misc/ShadowData.cs
rename to Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadowData.cs
index 64c49b34..3c58b366 100644
--- a/Source/Vehicles/CustomFeatures/AerialVehicles/Launching/Misc/ShadowData.cs
+++ b/Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadowData.cs
@@ -5,15 +5,15 @@
namespace Vehicles
{
- public class ShadowData
+ public struct DynamicShadowData
{
public float width;
public float height;
public float alpha;
- public static ShadowData CreateFrom(VehiclePawn vehicle)
+ public static DynamicShadowData CreateFrom(VehiclePawn vehicle)
{
- ShadowData shadowData = new ShadowData();
+ DynamicShadowData shadowData = new DynamicShadowData();
Vector2 shadowSize = vehicle.VehicleGraphic.data.drawSize;
shadowData.width = shadowSize.x;
shadowData.height = shadowSize.y;
diff --git a/Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadows.cs b/Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadows.cs
new file mode 100644
index 00000000..f4d1d1a2
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Misc/Rendering/DynamicShadows.cs
@@ -0,0 +1,91 @@
+using SmashTools;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+
+namespace Vehicles
+{
+ public static class DynamicShadows
+ {
+ private const float AlphaIsoThreshold = 0.5f;
+
+ private static readonly Dictionary shadowMeshDict = new Dictionary();
+
+ //TopLeft = 4th bit, TopRight = 3rd bit, BottomLeft = 1st bit, BottomRight = 2nd bit
+ //Result: able to loop CW from top left, but bit place starts bottom left and goes CCW for contour values
+ private static int[] bitArray = { 4, 3, 1, 2 };
+
+ public static Mesh GetShadowMesh(Texture2D texture, ShadowData shadowData)
+ {
+ return GetShadowMesh(texture, shadowData.BaseX, shadowData.BaseZ, shadowData.BaseY);
+ }
+
+ public static Mesh GetShadowMesh(Texture2D texture, float baseWidth, float baseHeight, float tallness)
+ {
+ int key = HashOf(texture, baseWidth, baseHeight, tallness);
+ if (!shadowMeshDict.TryGetValue(key, out Mesh mesh))
+ {
+ CreateMeshFromTexture(texture, baseWidth, baseHeight, tallness);
+ mesh = MeshMakerShadows.NewShadowMesh(baseWidth, baseHeight, tallness);
+ shadowMeshDict.Add(key, mesh);
+ }
+ return mesh;
+ }
+
+ ///
+ /// Generates mesh based on
+ ///
+ /// See https://en.wikipedia.org/wiki/Marching_squares for algorithm
+ public static Mesh CreateMeshFromTexture(Texture2D texture, float baseWidth, float baseHeight, float tallness)
+ {
+ Texture2D readableTex = Ext_Texture.CreateReadableTexture(texture);
+ try
+ {
+ Color[] texData = readableTex.GetPixels();
+
+ int width = texture.width - 1;
+ int height = texture.height - 1;
+ int[,] contourGrid = new int[width, height];
+ for (int x = 0; x < width; x++)
+ {
+ for (int y = 0; y < height; y++)
+ {
+ int value = 0;
+ //Get 4 corners of contour cell for bit value
+ for (int i = 0; i < 2; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ Color pixelColor = texData[(x + i) + (y + j)];
+ if (pixelColor.a >= AlphaIsoThreshold)
+ {
+ int contourIndex = bitArray[i + j];
+ value |= 1 << contourIndex; //Sets 2nd to 5th bit, or 1 -> 2 -> 4 -> 8 CCW starting from bottom left corner
+ }
+ }
+ }
+ //Final value between 0 and 15, depending on bit values of pixels. See link for mapping bit values to contour lines
+ contourGrid[x, y] = value;
+ }
+ }
+ }
+ finally
+ {
+ UnityEngine.Object.Destroy(readableTex);
+ }
+ return null;
+ }
+
+ private static int HashOf(Texture2D texture, float baseWidth, float baseheight, float tallness)
+ {
+ int num = (int)(baseWidth * 1000f);
+ int num2 = (int)(baseheight * 1000f);
+ int num3 = (int)(tallness * 1000f);
+ return Gen.HashCombineInt(num * 391 ^ 261231 ^ num2 * 612331 ^ num3 * 456123, texture.GetHashCode());
+ }
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Reservation/VehicleHandlerReservation.cs b/Source/Vehicles/CustomFeatures/Reservation/VehicleHandlerReservation.cs
index 49b3281c..985fcd9d 100644
--- a/Source/Vehicles/CustomFeatures/Reservation/VehicleHandlerReservation.cs
+++ b/Source/Vehicles/CustomFeatures/Reservation/VehicleHandlerReservation.cs
@@ -15,6 +15,8 @@ public class VehicleHandlerReservation : Reservation
private List pawnClaimants = new List();
private List claimantCounts = new List();
+ private static readonly List removeActors = new List();
+
public VehicleHandlerReservation()
{
}
@@ -55,10 +57,10 @@ public override bool AddClaimant(Pawn pawn, VehicleHandler target)
public override bool CanReserve(Pawn pawn, VehicleHandler target, StringBuilder stringBuilder = null)
{
int reservations = handlerClaimants.TryGetValue(target, 0);
- bool rolesAvailable = (target.handlers.Count + reservations) < target.role.slots;
+ bool rolesAvailable = (target.handlers.Count + reservations) < target.role.Slots;
if (!rolesAvailable)
{
- stringBuilder?.AppendLine($"Roles not available. Existing={target.handlers.Count} Claimants={string.Join(",", claimants.Where(kvp => kvp.Value == target).Select(kvp => kvp.Key))} Allowed: {target.role.slots}");
+ stringBuilder?.AppendLine($"Roles not available. Existing={target.handlers.Count} Claimants={string.Join(",", claimants.Where(kvp => kvp.Value == target).Select(kvp => kvp.Key))} Allowed: {target.role.Slots}");
return false;
}
if (pawn is null)
@@ -78,10 +80,13 @@ public override bool ReservedBy(Pawn pawn, VehicleHandler target)
public override void ReleaseAllReservations()
{
- foreach(Pawn p in claimants.Keys)
+ foreach (Pawn pawn in claimants.Keys)
{
- p.jobs.EndCurrentJob(JobCondition.InterruptForced);
- p.ClearMind();
+ if (pawn?.jobs != null)
+ {
+ pawn.jobs.EndCurrentJob(JobCondition.InterruptForced);
+ pawn.ClearMind();
+ }
}
}
@@ -99,23 +104,29 @@ public override void ReleaseReservationBy(Pawn pawn)
public override void VerifyAndValidateClaimants()
{
- List actors = new List(claimants.Keys);
- foreach (Pawn actor in actors)
+ removeActors.Clear();
+ foreach (Pawn actor in claimants.Keys)
{
Job matchedJob = actor.CurJob;
- if (actor.CurJob?.def != jobDef)
+ if (actor?.jobs != null && actor.CurJob?.def != jobDef)
{
matchedJob = actor.jobs.jobQueue?.FirstOrDefault(j => j.job.def == jobDef)?.job;
}
+
if (!actor.Spawned || actor.InMentalState || actor.Downed || actor.Dead || matchedJob?.def != jobDef || matchedJob?.targetA != targetA)
{
if (--handlerClaimants[claimants[actor]] <= 0)
{
handlerClaimants.Remove(claimants[actor]);
}
- claimants.Remove(actor);
+ removeActors.Add(actor);
}
}
+ foreach (Pawn removeActor in removeActors)
+ {
+ claimants.Remove(removeActor);
+ }
+ removeActors.Clear();
}
public override void ExposeData()
diff --git a/Source/Vehicles/CustomFeatures/Reservation/VehicleReservationManager.cs b/Source/Vehicles/CustomFeatures/Reservation/VehicleReservationManager.cs
index a1720d25..cc67c2d9 100644
--- a/Source/Vehicles/CustomFeatures/Reservation/VehicleReservationManager.cs
+++ b/Source/Vehicles/CustomFeatures/Reservation/VehicleReservationManager.cs
@@ -304,6 +304,9 @@ public override void ExposeData()
base.ExposeData();
Scribe_Collections.Look(ref reservations, nameof(reservations), LookMode.Reference, LookMode.Deep, ref vehiclesReserving_tmp, ref vehicleReservations_tmp);
Scribe_Collections.Look(ref vehicleListers, nameof(vehicleListers), LookMode.Reference, LookMode.Deep, ref vehicleListerPawns_tmp, ref vehicleListerRequests_tmp);
+
+ reservations ??= new Dictionary();
+ vehicleListers ??= new Dictionary();
}
///
diff --git a/Source/Vehicles/CustomFeatures/Spawner/VehicleSpawner.cs b/Source/Vehicles/CustomFeatures/Spawner/VehicleSpawner.cs
index f152fcbb..c55d5d2f 100644
--- a/Source/Vehicles/CustomFeatures/Spawner/VehicleSpawner.cs
+++ b/Source/Vehicles/CustomFeatures/Spawner/VehicleSpawner.cs
@@ -134,7 +134,7 @@ public static VehiclePawn SpawnVehicleRandomized(VehicleDef vehicleDef, IntVec3
if (autoFill)
{
- foreach (VehicleHandler handler in vehicle.handlers.Where(h => h.role.handlingTypes > HandlingTypeFlags.None))
+ foreach (VehicleHandler handler in vehicle.handlers.Where(h => h.role.HandlingTypes > HandlingTypeFlags.None))
{
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(PawnKindDefOf.Colonist, faction ));
pawn.SetFactionDirect(faction);
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/ActionUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/ActionUpgrade.cs
index 40dacd12..a8b3dde9 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/ActionUpgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/ActionUpgrade.cs
@@ -18,7 +18,7 @@ public class ActionUpgrade : Upgrade
public override bool UnlockOnLoad => unlockOnLoad;
- public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
{
if (!unlockMethods.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_Turret.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_Turret.cs
new file mode 100644
index 00000000..e2a159bc
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_Turret.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Vehicles
+{
+ public abstract class UpgradeSetting_Turret : UpgradeState.Setting
+ {
+ public string turretKey;
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_TurretRestriction.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_TurretRestriction.cs
new file mode 100644
index 00000000..28f2c491
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeSetting_TurretRestriction.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+
+namespace Vehicles
+{
+ public class UpgradeSetting_TurretRestriction : UpgradeSetting_Turret
+ {
+ public Type restrictionType;
+ public Operation operation;
+
+ public override void Unlocked(VehiclePawn vehicle, bool unlockingPostLoad)
+ {
+ VehicleTurret turret = vehicle.CompVehicleTurrets.GetTurret(turretKey);
+ if (turret == null)
+ {
+ Log.ErrorOnce($"Unable to locate turret with key={turretKey}. The turret must be part of the vehicle to add upgrades.", turretKey.GetHashCodeSafe());
+ return;
+ }
+ if (restrictionType != null)
+ {
+ switch (operation)
+ {
+ case Operation.Add:
+ turret.SetTurretRestriction(restrictionType);
+ break;
+ case Operation.Remove:
+ turret.RemoveTurretRestriction();
+ break;
+ }
+ }
+ }
+
+ public override void Refunded(VehiclePawn vehicle)
+ {
+ VehicleTurret turret = vehicle.CompVehicleTurrets.GetTurret(turretKey);
+ if (turret == null)
+ {
+ Log.ErrorOnce($"Unable to locate turret with key={turretKey}. The turret must be part of the vehicle to add upgrades.", turretKey.GetHashCodeSafe());
+ return;
+ }
+ if (restrictionType != null)
+ {
+ switch (operation)
+ {
+ case Operation.Add:
+ turret.RemoveTurretRestriction();
+ break;
+ case Operation.Remove:
+ turret.SetTurretRestriction(restrictionType);
+ break;
+ }
+ }
+ }
+
+ public enum Operation
+ {
+ Add,
+ Remove,
+ }
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeState.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeState.cs
new file mode 100644
index 00000000..71a66e24
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/Settings/UpgradeState.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Vehicles
+{
+ public class UpgradeState
+ {
+ public string key;
+ public List settings;
+
+ public abstract class Setting
+ {
+ public abstract void Unlocked(VehiclePawn vehicle, bool unlockingPostLoad);
+
+ public abstract void Refunded(VehiclePawn vehicle);
+ }
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/SettingsUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/SettingsUpgrade.cs
new file mode 100644
index 00000000..c3f8ece7
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/SettingsUpgrade.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using Verse;
+using SmashTools;
+using System.Runtime;
+
+namespace Vehicles
+{
+ public class SettingsUpgrade : Upgrade
+ {
+ public UpgradeState state;
+
+ public override bool UnlockOnLoad => true;
+
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
+ {
+ vehicle.CompUpgradeTree.AddSettings(state);
+
+ if (!state.settings.NullOrEmpty())
+ {
+ foreach (UpgradeState.Setting setting in state.settings)
+ {
+ setting.Unlocked(vehicle, unlockingPostLoad);
+ }
+ }
+ }
+
+ public override void Refund(VehiclePawn vehicle)
+ {
+ vehicle.CompUpgradeTree.RemoveSettings(state);
+
+ if (!state.settings.NullOrEmpty())
+ {
+ foreach (UpgradeState.Setting setting in state.settings)
+ {
+ setting.Refunded(vehicle);
+ }
+ }
+ }
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/SoundUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/SoundUpgrade.cs
index 33ad23d0..84d0fc4b 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/SoundUpgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/SoundUpgrade.cs
@@ -20,7 +20,7 @@ public class SoundUpgrade : Upgrade
public override bool UnlockOnLoad => true;
- public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
{
if (!removeOneShots.NullOrEmpty())
{
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/StatUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/StatUpgrade.cs
index 866175ec..664b75e4 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/StatUpgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/StatUpgrade.cs
@@ -5,6 +5,8 @@
using Verse;
using RimWorld;
using SmashTools;
+using static Vehicles.StatUpgrade;
+using static System.Net.Mime.MediaTypeNames;
namespace Vehicles
{
@@ -18,7 +20,56 @@ public class StatUpgrade : Upgrade
public override bool UnlockOnLoad => true;
- public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
+ public override IEnumerable UpgradeDescription(VehiclePawn vehicle)
+ {
+ if (!stats.NullOrEmpty())
+ {
+ foreach (StatDefUpgrade statDefUpgrade in stats)
+ {
+ switch (statDefUpgrade.type)
+ {
+ case UpgradeType.Add:
+ yield return new UpgradeTextEntry(statDefUpgrade.def.LabelCap, statDefUpgrade.ValueFormatted, statDefUpgrade.value, UpgradeEffectType.Positive);
+ break;
+ case UpgradeType.Set:
+ yield return new UpgradeTextEntry(statDefUpgrade.def.LabelCap, statDefUpgrade.value.ToString());
+ break;
+ }
+ }
+ }
+ if (!vehicleStats.NullOrEmpty())
+ {
+ foreach (VehicleStatDefUpgrade vehicleStatDefUpgrade in vehicleStats)
+ {
+ switch (vehicleStatDefUpgrade.type)
+ {
+ case UpgradeType.Add:
+ yield return new UpgradeTextEntry(vehicleStatDefUpgrade.def.LabelCap, vehicleStatDefUpgrade.ValueFormatted, vehicleStatDefUpgrade.value, vehicleStatDefUpgrade.def.upgradeEffectType);
+ break;
+ case UpgradeType.Set:
+ yield return new UpgradeTextEntry(vehicleStatDefUpgrade.def.LabelCap, vehicleStatDefUpgrade.value.ToString());
+ break;
+ }
+ }
+ }
+ if (!statCategories.NullOrEmpty())
+ {
+ foreach (StatCategoryUpgrade statCategoryUpgrade in statCategories)
+ {
+ switch (statCategoryUpgrade.type)
+ {
+ case UpgradeType.Add:
+ yield return new UpgradeTextEntry(statCategoryUpgrade.def.LabelCap, statCategoryUpgrade.ValueFormatted, statCategoryUpgrade.value, statCategoryUpgrade.def.upgradeEffectType);
+ break;
+ case UpgradeType.Set:
+ yield return new UpgradeTextEntry(statCategoryUpgrade.def.LabelCap, statCategoryUpgrade.value.ToString());
+ break;
+ }
+ }
+ }
+ }
+
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
{
if (!stats.NullOrEmpty())
{
@@ -126,6 +177,23 @@ public class StatDefUpgrade
public float value;
public UpgradeType type;
+
+ public string ValueFormatted
+ {
+ get
+ {
+ string text = value.ToStringByStyle(def.toStringStyle, numberSense: def.toStringNumberSense);
+ if (def.toStringNumberSense != ToStringNumberSense.Factor && !def.formatString.NullOrEmpty())
+ {
+ text = string.Format(def.formatString, text);
+ }
+ if (type == UpgradeType.Add && value > 0)
+ {
+ text = "+" + text;
+ }
+ return text;
+ }
+ }
}
public class VehicleStatDefUpgrade
@@ -134,6 +202,14 @@ public class VehicleStatDefUpgrade
public float value;
public UpgradeType type;
+
+ public string ValueFormatted
+ {
+ get
+ {
+ return UpgradeTextEntry.FormatValue(value, type, def.toStringStyle, def.toStringNumberSense, def.formatString);
+ }
+ }
}
public class StatCategoryUpgrade
@@ -142,6 +218,14 @@ public class StatCategoryUpgrade
public float value;
public UpgradeType type;
+
+ public string ValueFormatted
+ {
+ get
+ {
+ return UpgradeTextEntry.FormatValue(value, type, def.toStringStyle, def.toStringNumberSense, def.formatString);
+ }
+ }
}
}
}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/TurretUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/TurretUpgrade.cs
index aee699ca..f0f44d2e 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/TurretUpgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/TurretUpgrade.cs
@@ -4,6 +4,7 @@
using UnityEngine;
using Verse;
using SmashTools;
+using System.Runtime;
namespace Vehicles
{
@@ -12,32 +13,37 @@ public class TurretUpgrade : Upgrade
public readonly List turrets;
public readonly List removeTurrets;
-
+
public override bool UnlockOnLoad => false;
- public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
+ public override bool HasGraphics => turrets.NotNullAndAny(turret => !turret.NoGraphic) || !removeTurrets.NullOrEmpty();
+
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
{
- if (!turrets.NullOrEmpty())
+ if (!unlockingPostLoad)
{
- foreach (VehicleTurret turret in turrets)
+ if (!removeTurrets.NullOrEmpty())
{
- try
+ foreach (string key in removeTurrets)
{
- vehicle.CompVehicleTurrets.AddTurret(turret);
- }
- catch (Exception ex)
- {
- Log.Error($"{VehicleHarmony.LogLabel} Unable to unlock {GetType()} to {vehicle.LabelShort}. \nException: {ex}");
+ if (!vehicle.CompVehicleTurrets.RemoveTurret(key))
+ {
+ Log.Error($"Unable to remove {key} from {vehicle}. Turret not found.");
+ }
}
}
- }
- if (!removeTurrets.NullOrEmpty())
- {
- foreach (string key in removeTurrets)
+ if (!turrets.NullOrEmpty())
{
- if (!vehicle.CompVehicleTurrets.RemoveTurret(key))
+ foreach (VehicleTurret turret in turrets)
{
- Log.Warning($"Unable to remove {key} from {vehicle}. Turret not found.");
+ try
+ {
+ vehicle.CompVehicleTurrets.AddTurret(turret, node.key);
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"{VehicleHarmony.LogLabel} Unable to unlock {GetType()} to {vehicle.LabelShort}. \nException: {ex}");
+ }
}
}
}
@@ -52,7 +58,22 @@ public override void Refund(VehiclePawn vehicle)
{
if (!vehicle.CompVehicleTurrets.RemoveTurret(turret.key))
{
- Log.Warning($"Unable to remove {turret.key} from {vehicle}. Turret not found.");
+ Log.Error($"Unable to remove {turret.key} from {vehicle}. Turret not found.");
+ }
+ }
+ }
+ if (!removeTurrets.NullOrEmpty())
+ {
+ foreach (string key in removeTurrets)
+ {
+ VehicleTurret turret = vehicle.CompVehicleTurrets.Props.turrets.FirstOrDefault(turret => turret.key == key);
+ if (turret == null)
+ {
+ Log.Error($"Unable to add {key} to {vehicle}. Turret must be defined in the VehicleDef in order to be re-added post-refund.");
+ }
+ else
+ {
+ vehicle.CompVehicleTurrets.AddTurret(turret);
}
}
}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/Upgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/Upgrade.cs
index 60879f6b..143cec17 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/Upgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/Upgrade.cs
@@ -12,10 +12,25 @@ public abstract class Upgrade
public abstract bool UnlockOnLoad { get; }
+ public virtual bool HasGraphics => false;
+
+ public virtual IEnumerable ConfigErrors
+ {
+ get
+ {
+ yield break;
+ }
+ }
+
+ public virtual IEnumerable UpgradeDescription(VehiclePawn vehicle)
+ {
+ yield break;
+ }
+
///
/// Called when node has upgraded fully, after upgrade build ticks hits 0 or triggered by god mode
///
- public abstract void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad);
+ public abstract void Unlock(VehiclePawn vehicle, bool unlockingPostLoad);
///
/// Undo Upgrade action. Should be polar opposite of Upgrade functionality to revert changes
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/Node/VehicleUpgrade.cs b/Source/Vehicles/CustomFeatures/Upgrades/Node/VehicleUpgrade.cs
index f2d586ad..9458b325 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/Node/VehicleUpgrade.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/Node/VehicleUpgrade.cs
@@ -4,6 +4,10 @@
using Verse;
using Verse.Sound;
using RimWorld;
+using SmashTools;
+using Verse.Grammar;
+using static Vehicles.VehicleUpgrade;
+using System.Security.Cryptography;
namespace Vehicles
{
@@ -13,15 +17,50 @@ public class VehicleUpgrade : Upgrade
public List health;
- public List roles; //TODO - VehicleHandler needs some changes to allow resolving roles from upgrades
+ public List roles;
+
+ public RetextureDef retextureDef;
public override bool UnlockOnLoad => true;
- public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
+ public override IEnumerable UpgradeDescription(VehiclePawn vehicle)
{
- if (!roles.NullOrEmpty())
+ if (!armor.NullOrEmpty())
{
+ foreach (ArmorUpgrade armorUpgrade in armor)
+ {
+ if (!armorUpgrade.key.NullOrEmpty() && !armorUpgrade.statModifiers.NullOrEmpty())
+ {
+ VehicleComponent component = vehicle.statHandler.GetComponent(armorUpgrade.key);
+ switch (armorUpgrade.type)
+ {
+ case UpgradeType.Add:
+ foreach (UpgradeTextEntry textEntry in armorUpgrade.UpgradeEntries(vehicle, component))
+ {
+ yield return textEntry;
+ }
+ break;
+ case UpgradeType.Set:
+ component.SetArmorModifiers[node.key] = armorUpgrade.statModifiers;
+ break;
+ }
+ }
+ }
+ }
+ }
+ public override void Unlock(VehiclePawn vehicle, bool unlockingPostLoad)
+ {
+ if (!roles.NullOrEmpty()) //Roles are serialized as VehicleHandler, no need to re-upgrade
+ {
+ foreach (RoleUpgrade roleUpgrade in roles)
+ {
+ UpgradeRole(vehicle, roleUpgrade, false, unlockingPostLoad);
+ }
+ }
+ if (retextureDef != null && !unlockingPostLoad)
+ {
+ vehicle.SetRetexture(retextureDef);
}
if (!armor.NullOrEmpty())
{
@@ -49,14 +88,24 @@ public override void Unlock(VehiclePawn vehicle, bool unlockingAfterLoad)
if (!healthUpgrade.key.NullOrEmpty())
{
VehicleComponent component = vehicle.statHandler.GetComponent(healthUpgrade.key);
- switch (healthUpgrade.type)
+
+ if (healthUpgrade.value.HasValue)
{
- case UpgradeType.Add:
- component.AddHealthModifiers[node.key] = healthUpgrade.value;
- break;
- case UpgradeType.Set:
- component.SetHealthModifier = healthUpgrade.value;
- break;
+ switch (healthUpgrade.type)
+ {
+ case UpgradeType.Add:
+ component.AddHealthModifiers[node.key] = healthUpgrade.value.Value;
+ break;
+ case UpgradeType.Set:
+ component.SetHealthModifier = healthUpgrade.value.Value;
+ break;
+ }
+ }
+
+
+ if (healthUpgrade.depth != null)
+ {
+ component.depthOverride = healthUpgrade.depth;
}
}
}
@@ -67,7 +116,14 @@ public override void Refund(VehiclePawn vehicle)
{
if (!roles.NullOrEmpty())
{
-
+ foreach (RoleUpgrade roleUpgrade in roles)
+ {
+ UpgradeRole(vehicle, roleUpgrade, true, false);
+ }
+ }
+ if (retextureDef != null)
+ {
+ vehicle.SetRetexture(null);
}
if (!armor.NullOrEmpty())
{
@@ -88,6 +144,84 @@ public override void Refund(VehiclePawn vehicle)
}
}
}
+ if (!health.NullOrEmpty())
+ {
+ foreach (HealthUpgrade healthUpgrade in health)
+ {
+ if (!healthUpgrade.key.NullOrEmpty())
+ {
+ VehicleComponent component = vehicle.statHandler.GetComponent(healthUpgrade.key);
+
+ if (healthUpgrade.value.HasValue)
+ {
+ switch (healthUpgrade.type)
+ {
+ case UpgradeType.Add:
+ component.AddHealthModifiers.Remove(node.key);
+ break;
+ case UpgradeType.Set:
+ component.SetHealthModifier = -1;
+ break;
+ }
+ }
+
+
+ if (healthUpgrade.depth != null)
+ {
+ component.depthOverride = null;
+ }
+ }
+ }
+ }
+ }
+
+ public void UpgradeRole(VehiclePawn vehicle, RoleUpgrade roleUpgrade, bool isRefund, bool unlockingAfterLoad)
+ {
+ bool needsRemoval = roleUpgrade.remove ^ isRefund; //XOR operation for inverse behavior of removal upgrades
+ if (needsRemoval)
+ {
+ VehicleHandler handler = vehicle.GetHandler(roleUpgrade.key);
+ if (!roleUpgrade.editKey.NullOrEmpty())
+ {
+ if (handler == null)
+ {
+ Log.Error($"Unable to edit {roleUpgrade.editKey}. Matching VehicleRole not found.");
+ return;
+ }
+ handler.role.RemoveUpgrade(roleUpgrade);
+ }
+ else if (!unlockingAfterLoad)
+ {
+ if (handler == null)
+ {
+ Log.Error($"Unable to remove {roleUpgrade.key} from {vehicle.Name}. Role not found.");
+ return;
+ }
+ vehicle.RemoveRole(roleUpgrade.key);
+ }
+ }
+ else
+ {
+ VehicleHandler handler = vehicle.GetHandler(roleUpgrade.key);
+ if (!roleUpgrade.editKey.NullOrEmpty())
+ {
+ if (handler == null)
+ {
+ Log.Error($"Unable to edit {roleUpgrade.editKey}. Matching VehicleRole not found.");
+ return;
+ }
+ handler.role.AddUpgrade(roleUpgrade);
+ }
+ else if (!unlockingAfterLoad)
+ {
+ if (handler != null)
+ {
+ Log.Error($"Attempting to create new role with existing key. If the upgrade is for modifying an existing role, an editKey must be specified.");
+ return;
+ }
+ vehicle.AddRole(RoleUpgrade.RoleFromUpgrade(roleUpgrade));
+ }
+ }
}
public struct ArmorUpgrade
@@ -96,14 +230,76 @@ public struct ArmorUpgrade
public List statModifiers;
public UpgradeType type;
+
+ public IEnumerable UpgradeEntries(VehiclePawn vehicle, VehicleComponent component)
+ {
+ if (!statModifiers.NullOrEmpty())
+ {
+ foreach (StatModifier statModifier in statModifiers)
+ {
+ string valueFormatted = UpgradeTextEntry.FormatValue(statModifier.value, type, statModifier.stat.toStringStyle, statModifier.stat.toStringNumberSense, statModifier.stat.formatString);
+ yield return new UpgradeTextEntry($"{statModifier.stat.LabelCap} ({component.props.label})", valueFormatted, UpgradeEffectType.Positive);
+ }
+ }
+ }
}
public struct HealthUpgrade
{
public string key;
- public float value;
+ public int? value;
+
+ public VehicleComponent.VehiclePartDepth? depth;
public UpgradeType type;
+
+ public IEnumerable UpgradeEntries(VehiclePawn vehicle, VehicleComponent component)
+ {
+ if (value != null)
+ {
+ string valueFormatted = UpgradeTextEntry.FormatValue(value.Value, type, ToStringStyle.Integer);
+ yield return new UpgradeTextEntry($"{component.props.label}", valueFormatted, UpgradeEffectType.Positive);
+ }
+ if (depth != null)
+ {
+ yield return new UpgradeTextEntry($"{component.props.label}", $"{"Depth".Translate()} = {depth.Value.Translate()}");
+ }
+ }
+ }
+
+ public class RoleUpgrade
+ {
+ public string key;
+ public string label = "[MissingLabel]";
+ public string editKey;
+
+ public bool remove = false;
+
+ //Operating
+ public HandlingTypeFlags? handlingTypes;
+ public int? slots;
+ public int? slotsToOperate;
+ public float? comfort;
+ public List turretIds;
+
+ //Damaging
+ public ComponentHitbox hitbox;
+ public bool? exposed;
+ public float? chanceToHit;
+
+ //Rendering
+ public PawnOverlayRenderer pawnRenderer;
+
+ public static VehicleRole RoleFromUpgrade(RoleUpgrade upgrade)
+ {
+ VehicleRole role = new VehicleRole()
+ {
+ key = upgrade.key,
+ label = upgrade.label
+ };
+ role.CopyFrom(upgrade);
+ return role;
+ }
}
}
}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/StatUpgradeCategoryDef.cs b/Source/Vehicles/CustomFeatures/Upgrades/StatUpgradeCategoryDef.cs
index 9a65f010..a3360777 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/StatUpgradeCategoryDef.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/StatUpgradeCategoryDef.cs
@@ -10,5 +10,11 @@ namespace Vehicles
{
public class StatUpgradeCategoryDef : Def
{
+ public ToStringStyle toStringStyle = ToStringStyle.FloatTwo;
+ public ToStringNumberSense toStringNumberSense = ToStringNumberSense.Absolute;
+ [MustTranslate]
+ public string formatString;
+
+ public UpgradeEffectType upgradeEffectType = UpgradeEffectType.Positive;
}
}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeEffectType.cs b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeEffectType.cs
new file mode 100644
index 00000000..4938798f
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeEffectType.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Vehicles
+{
+ public enum UpgradeEffectType
+ {
+ Positive,
+ Negative,
+ Neutral,
+ None,
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeNode.cs b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeNode.cs
index 99779095..0ef15236 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeNode.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeNode.cs
@@ -13,6 +13,7 @@ public class UpgradeNode
public string key;
public string label;
public string description;
+ public string upgradeExplanation;
public bool displayLabel = false;
public string icon;
@@ -34,7 +35,7 @@ public class UpgradeNode
public List replaces;
- public string disableIfUpgradeNodeEnabled;
+ public string disableIfUpgradeNodeEnabled; //TODO - Remove in 1.6 in favor of disable conditions
public List researchPrerequisites = new List();
public List prerequisiteNodes = new List();
@@ -46,6 +47,8 @@ public class UpgradeNode
public virtual IntVec2 GridCoordinate => gridCoordinate;
+ public bool HasGraphics { get; private set; }
+
public virtual Texture2D UpgradeImage
{
get
@@ -74,6 +77,18 @@ public virtual void DrawExtraOnGUI(Rect rect)
/// Apply texture overlays and colors
///
public void AddOverlays(VehiclePawn vehicle)
+ {
+ if (!UnityData.IsInMainThread)
+ {
+ LongEventHandler.ExecuteWhenFinished(() => AddOverlaysInternal(vehicle));
+ }
+ else
+ {
+ AddOverlaysInternal(vehicle);
+ }
+ }
+
+ private void AddOverlaysInternal(VehiclePawn vehicle)
{
if (!graphicOverlays.NullOrEmpty())
{
@@ -245,11 +260,13 @@ public IEnumerable MaterialsRequired(VehiclePawn vehicle)
public void ResolveReferences()
{
+ HasGraphics = !graphicOverlays.NullOrEmpty();
if (!upgrades.NullOrEmpty())
{
foreach (Upgrade upgrade in upgrades)
{
upgrade.Init(this);
+ HasGraphics |= upgrade.HasGraphics;
}
}
}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTextEntry.cs b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTextEntry.cs
new file mode 100644
index 00000000..48d1ef79
--- /dev/null
+++ b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTextEntry.cs
@@ -0,0 +1,70 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+
+namespace Vehicles
+{
+ public struct UpgradeTextEntry
+ {
+ public string label;
+ public string description;
+ public UpgradeEffectType effectType;
+
+ public UpgradeTextEntry(string label, string description, UpgradeEffectType effectType = UpgradeEffectType.None)
+ {
+ this.label = label;
+ this.description = description;
+ this.effectType = effectType;
+ }
+
+ public UpgradeTextEntry(string label, string description, float value, UpgradeEffectType effectType)
+ {
+ this.label = label;
+ this.description = description;
+
+ switch (effectType)
+ {
+ case UpgradeEffectType.Positive:
+ this.effectType = EffectTypeFromValue(value);
+ break;
+ case UpgradeEffectType.Negative:
+ this.effectType = EffectTypeFromValue(-value); //Inverts value for opposite effect types as Positive
+ break;
+ default:
+ this.effectType = effectType;
+ break;
+ }
+ }
+
+ private static UpgradeEffectType EffectTypeFromValue(float value)
+ {
+ if (value > 0)
+ {
+ return UpgradeEffectType.Positive;
+ }
+ else if (value < 0)
+ {
+ return UpgradeEffectType.Negative;
+ }
+ return UpgradeEffectType.None;
+ }
+
+ public static string FormatValue(float value, UpgradeType upgradeType, ToStringStyle toStringStyle, ToStringNumberSense toStringNumberSense = ToStringNumberSense.Absolute, string formatString = null)
+ {
+ string text = value.ToStringByStyle(toStringStyle, numberSense: toStringNumberSense);
+ if (toStringNumberSense != ToStringNumberSense.Factor && !formatString.NullOrEmpty())
+ {
+ text = string.Format(formatString, text);
+ }
+ if (upgradeType == UpgradeType.Add && value > 0)
+ {
+ text = "+" + text;
+ }
+ return text;
+ }
+ }
+}
diff --git a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTreeDef.cs b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTreeDef.cs
index d9361c01..8946483c 100644
--- a/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTreeDef.cs
+++ b/Source/Vehicles/CustomFeatures/Upgrades/UpgradeTreeDef.cs
@@ -32,6 +32,16 @@ public override IEnumerable ConfigErrors()
}
}
}
+ if (!node.upgrades.NullOrEmpty())
+ {
+ foreach (Upgrade upgrade in node.upgrades)
+ {
+ foreach (string error in upgrade.ConfigErrors)
+ {
+ yield return $"(UpgradeNode={node.key} Type={upgrade.GetType()}) {error}";
+ }
+ }
+ }
}
}
}
diff --git a/Source/Vehicles/Gizmo/Command_CooldownAction.cs b/Source/Vehicles/Gizmo/Command_CooldownAction.cs
index 752654e9..0a9f4de2 100644
--- a/Source/Vehicles/Gizmo/Command_CooldownAction.cs
+++ b/Source/Vehicles/Gizmo/Command_CooldownAction.cs
@@ -208,20 +208,20 @@ protected virtual float DrawGizmoButton(Rect rect, Material cooldownMaterial, ou
GUIState.Push();
{
Rect turretRect = gizmoRect.ContractedBy(2);
- (Rect rect, Texture mainTex, Color color, float layer, float angle) turretProps;
+ VehicleGUI.RenderData turretRenderData;
if (turret.turretDef.gizmoIconTexPath.NullOrEmpty())
{
- turretProps = VehicleGUI.RetrieveTurretSettingsGUIProperties(turretRect, vehicle.VehicleDef, turret, Rot8.North, vehicle.patternData, iconScale: iconDrawScale);
+ turretRenderData = VehicleGUI.RetrieveTurretSettingsGUIProperties(turretRect, vehicle.VehicleDef, turret, Rot8.North, vehicle.patternData, iconScale: iconDrawScale);
}
else
{
- turretProps = (new Rect(0, 0, turretRect.width, turretRect.height), turret.GizmoIcon, Color.white, 1, 0);
+ turretRenderData = new VehicleGUI.RenderData(new Rect(0, 0, turretRect.width, turretRect.height), turret.GizmoIcon, Color.white, 1, 0);
}
Widgets.BeginGroup(turretRect);
{
- GUI.color = turretProps.color;
+ GUI.color = turretRenderData.color;
//Draw turret facing North for gizmos
- UIElements.DrawTextureWithMaterialOnGUI(turretRect.AtZero().ExpandedBy(turretRect.width * (iconDrawScale - 1)), turretProps.mainTex, null, 0);
+ UIElements.DrawTextureWithMaterialOnGUI(turretRect.AtZero().ExpandedBy(turretRect.width * (iconDrawScale - 1)), turretRenderData.mainTex, null, 0);
}
Widgets.EndGroup();
}
diff --git a/Source/Vehicles/Graphics/Dialogs/Dialog_AssignSeats.cs b/Source/Vehicles/Graphics/Dialogs/Dialog_AssignSeats.cs
index 13b7d125..0adb878d 100644
--- a/Source/Vehicles/Graphics/Dialogs/Dialog_AssignSeats.cs
+++ b/Source/Vehicles/Graphics/Dialogs/Dialog_AssignSeats.cs
@@ -152,14 +152,14 @@ private void DrawPawns(Rect rect)
{
DrawPawnRow(pawnRowRect, pawn, (ButtonHeight * 3, "VF_AddToRole".Translate(), delegate()
{
- bool Validate(VehicleHandler handler) => assignedSeats.Where(seat => seat.Value.handler.role == handler.role).Select(p => p.Key).Count() < handler.role.slots;
+ bool Validate(VehicleHandler handler) => assignedSeats.Where(seat => seat.Value.handler.role == handler.role).Select(p => p.Key).Count() < handler.role.Slots;
VehicleHandler firstHandler = Vehicle.handlers.FirstOrDefault(handler => handler.CanOperateRole(pawn) && Validate(handler));
firstHandler ??= Vehicle.handlers.FirstOrDefault(handler => !handler.RequiredForMovement && Validate(handler));
if (firstHandler != null)
{
if (!firstHandler.CanOperateRole(pawn))
{
- if (firstHandler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement))
+ if (firstHandler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement))
{
Messages.Message("VF_IncapableStatusForRole".Translate(pawn.LabelShortCap), MessageTypeDefOf.RejectInput);
}
@@ -186,7 +186,7 @@ private void DrawPawns(Rect rect)
private void DrawAssignees(Rect rect)
{
Widgets.Label(rect, "VF_Assigned".Translate());
- Predicate seatsAvailable = (handler) => assignedSeats.Where(seat => seat.Value.handler.role == handler.role).Select(p => p.Key).Count() < handler.role.slots;
+ Predicate seatsAvailable = (handler) => assignedSeats.Where(seat => seat.Value.handler.role == handler.role).Select(p => p.Key).Count() < handler.role.Slots;
Rect pawnRowRect = new Rect(rect.x, rect.y + RowHeight + 5, rect.width - 1, RowHeight);
Rect outRect = new Rect(pawnRowRect)
{
@@ -203,9 +203,9 @@ private void DrawAssignees(Rect rect)
foreach (VehicleHandler handler in Vehicle.handlers)
{
int seatsOccupied = assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(p => p.Key).Count();
- Color countColor = handler.role.RequiredForCaravan ? seatsOccupied < handler.role.slotsToOperate ? Color.red : seatsOccupied == handler.role.slots ? Color.grey : Color.white : seatsOccupied == handler.role.slots ? Color.grey : Color.white;
+ Color countColor = handler.role.RequiredForCaravan ? seatsOccupied < handler.role.SlotsToOperate ? Color.red : seatsOccupied == handler.role.Slots ? Color.grey : Color.white : seatsOccupied == handler.role.Slots ? Color.grey : Color.white;
- UIElements.LabelUnderlined(pawnRowRect, handler.role.label, $"({handler.role.slots - assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(p => p.Key).Count()})", Color.white, countColor, Color.white);
+ UIElements.LabelUnderlined(pawnRowRect, handler.role.label, $"({handler.role.Slots - assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(p => p.Key).Count()})", Color.white, countColor, Color.white);
pawnRowRect.y += RowHeight;
Rect roleRect = new Rect(pawnRowRect.x, pawnRowRect.y, pawnRowRect.width, RowHeight + RowHeight * assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(p => p.Key).Count());
@@ -215,9 +215,9 @@ private void DrawAssignees(Rect rect)
{
if (Event.current.type == EventType.MouseUp && Event.current.button == 0)
{
- if (handler.role.handlingTypes > HandlingTypeFlags.None && !draggedPawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || draggedPawn.Downed || draggedPawn.Dead)
+ if (handler.role.HandlingTypes > HandlingTypeFlags.None && !draggedPawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || draggedPawn.Downed || draggedPawn.Dead)
{
- if (handler.role.handlingTypes.HasFlag(HandlingTypeFlags.Movement))
+ if (handler.role.HandlingTypes.HasFlag(HandlingTypeFlags.Movement))
{
Messages.Message("VF_IncapableStatusForRole".Translate(draggedPawn.LabelShortCap), MessageTypeDefOf.RejectInput);
}
@@ -291,7 +291,7 @@ private bool FinalizeSeats(out string failReason)
failReason = string.Empty;
foreach (VehicleHandler handler in Vehicle.handlers.Where(x => x.role.RequiredForCaravan))
{
- if (assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(k => k.Key).Count() < handler.role.slotsToOperate)
+ if (assignedSeats.Where(r => r.Value.handler.role == handler.role).Select(k => k.Key).Count() < handler.role.SlotsToOperate)
{
failReason = "VF_CantAssignVehicle".Translate(Vehicle.LabelCap);
return false;
diff --git a/Source/Vehicles/Graphics/Dialogs/Dialog_ColorPicker.cs b/Source/Vehicles/Graphics/Dialogs/Dialog_ColorPicker.cs
index 07f9f831..6af80b94 100644
--- a/Source/Vehicles/Graphics/Dialogs/Dialog_ColorPicker.cs
+++ b/Source/Vehicles/Graphics/Dialogs/Dialog_ColorPicker.cs
@@ -507,7 +507,7 @@ private void DrawColorPalette(Rect rect)
private void DoBottomButtons(Rect buttonRect)
{
- if (Widgets.ButtonText(buttonRect, "ApplyButton".Translate()))
+ if (Widgets.ButtonText(buttonRect, "VF_ApplyButton".Translate()))
{
OnSave(CurrentColorOne.ToColor, CurrentColorTwo.ToColor, CurrentColorThree.ToColor, selectedPattern, new Vector2(displacementX, displacementY), additionalTiling);
Close(true);
diff --git a/Source/Vehicles/Graphics/Dialogs/Dialog_FormVehicleCaravan.cs b/Source/Vehicles/Graphics/Dialogs/Dialog_FormVehicleCaravan.cs
index eb87f833..fe7dbb0f 100644
--- a/Source/Vehicles/Graphics/Dialogs/Dialog_FormVehicleCaravan.cs
+++ b/Source/Vehicles/Graphics/Dialogs/Dialog_FormVehicleCaravan.cs
@@ -557,7 +557,7 @@ private void DoBottomButtons(Rect rect)
else
{
List vehiclesFromTransferables = TransferableUtility.GetPawnsFromTransferables(transferables).Where(pawn => pawn is VehiclePawn).Cast().ToList();
- if (vehiclesFromTransferables.Any(vehicle => !Find.World.GetCachedWorldComponent().PassableFast(map.Tile, vehicle.VehicleDef)))
+ if (vehiclesFromTransferables.Any(vehicle => !Find.World.GetComponent().PassableFast(map.Tile, vehicle.VehicleDef)))
{
Messages.Message("MessageNoValidExitTile".Translate(), MessageTypeDefOf.RejectInput, false);
return;
@@ -605,7 +605,7 @@ private void CalculateAndRecacheTransferables()
private bool DebugTryFormCaravanInstantly()
{
List vehiclesFromTransferables = TransferableUtility.GetPawnsFromTransferables(transferables).Where(pawn => pawn is VehiclePawn).Cast().ToList();
- if (vehiclesFromTransferables.Any(vehicle => !Find.World.GetCachedWorldComponent().PassableFast(map.Tile, vehicle.VehicleDef)))
+ if (vehiclesFromTransferables.Any(vehicle => !Find.World.GetComponent().PassableFast(map.Tile, vehicle.VehicleDef)))
{
Messages.Message("MessageNoValidExitTile".Translate(), MessageTypeDefOf.RejectInput, false);
return false;
diff --git a/Source/Vehicles/Graphics/Dialogs/Dialog_StashVehicle.cs b/Source/Vehicles/Graphics/Dialogs/Dialog_StashVehicle.cs
index d2d7e7fc..bf4260fb 100644
--- a/Source/Vehicles/Graphics/Dialogs/Dialog_StashVehicle.cs
+++ b/Source/Vehicles/Graphics/Dialogs/Dialog_StashVehicle.cs
@@ -393,7 +393,7 @@ private bool TransferPawns()
stashedVehicle.Tile = caravan.Tile;
//Calculate days before removal from map
- VehiclePawn largestVehicle = caravan.Vehicles.MaxBy(vehicle => vehicle.VehicleDef.Size.Magnitude);
+ VehiclePawn largestVehicle = caravan.VehiclesListForReading.MaxBy(vehicle => vehicle.VehicleDef.Size.Magnitude);
float t = Ext_Math.ReverseInterpolate(largestVehicle.VehicleDef.Size.Magnitude, 1, 10);
float timeoutDays = 25 * Mathf.Lerp(1.2f, 0.8f, t); //20 to 30 days depending on size of vehicle
stashedVehicle.GetComponent().StartTimeout(Mathf.CeilToInt(timeoutDays * 60000));
@@ -467,7 +467,7 @@ private bool CheckForErrors(List pawns)
private void AddItemsToTransferables()
{
- foreach (VehiclePawn vehicle in caravan.Vehicles)
+ foreach (VehiclePawn vehicle in caravan.VehiclesListForReading)
{
foreach (Thing thing in vehicle.inventory.innerContainer)
{
diff --git a/Source/Vehicles/Graphics/Graphic/GraphicData/GraphicDataLayered.cs b/Source/Vehicles/Graphics/Graphic/GraphicData/GraphicDataLayered.cs
index 94f5d730..91c268c4 100644
--- a/Source/Vehicles/Graphics/Graphic/GraphicData/GraphicDataLayered.cs
+++ b/Source/Vehicles/Graphics/Graphic/GraphicData/GraphicDataLayered.cs
@@ -31,9 +31,26 @@ public virtual void CopyFrom(GraphicDataLayered graphicData)
{
base.CopyFrom(graphicData);
layer = graphicData.layer;
+ ResetDrawOffsetCache();
}
public virtual void Init(IMaterialCacheTarget target)
+ {
+ RecacheLayerOffsets();
+ }
+
+ private void ResetDrawOffsetCache()
+ {
+ OriginalDrawOffset = null;
+ OriginalDrawOffsetNorth = null;
+ OriginalDrawOffsetEast = null;
+ OriginalDrawOffsetSouth = null;
+ OriginalDrawOffsetWest = null;
+
+ RecacheLayerOffsets();
+ }
+
+ public void RecacheLayerOffsets()
{
OriginalDrawOffset ??= drawOffset;
OriginalDrawOffsetNorth ??= drawOffsetNorth;
diff --git a/Source/Vehicles/Graphics/Graphic/GraphicGeneration/GraphicDatabaseRGB.cs b/Source/Vehicles/Graphics/Graphic/GraphicGeneration/GraphicDatabaseRGB.cs
index 55450b17..3cbb6b8d 100644
--- a/Source/Vehicles/Graphics/Graphic/GraphicGeneration/GraphicDatabaseRGB.cs
+++ b/Source/Vehicles/Graphics/Graphic/GraphicGeneration/GraphicDatabaseRGB.cs
@@ -48,6 +48,11 @@ public static Graphic_RGB Get(IMaterialCacheTarget target, Type graphicClass, st
return (T)graphic;
}
+ public static bool Remove(IMaterialCacheTarget target)
+ {
+ return allGraphics.Remove(target);
+ }
+
public static void Clear()
{
allGraphics.Clear();
diff --git a/Source/Vehicles/Graphics/Graphic/Graphics/VanillaSupported/Graphic_DynamicShadow.cs b/Source/Vehicles/Graphics/Graphic/Graphics/VanillaSupported/Graphic_DynamicShadow.cs
new file mode 100644
index 00000000..23cdbcee
--- /dev/null
+++ b/Source/Vehicles/Graphics/Graphic/Graphics/VanillaSupported/Graphic_DynamicShadow.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using LudeonTK;
+
+namespace Vehicles
+{
+ public class Graphic_DynamicShadow : Graphic
+ {
+ private readonly ShadowData shadowData;
+
+ private Mesh shadowMesh;
+
+ public Graphic_DynamicShadow(Texture2D texture, ShadowData shadowData)
+ {
+ this.shadowData = shadowData;
+ if (shadowData == null)
+ {
+ throw new ArgumentNullException(nameof(shadowData));
+ }
+ shadowMesh = DynamicShadows.GetShadowMesh(texture, shadowData);
+ }
+
+ public override void DrawWorker(Vector3 loc, Rot4 rot, ThingDef thingDef, Thing thing, float extraRotation)
+ {
+ if (shadowMesh != null && shadowData != null && (Find.CurrentMap == null || !loc.ToIntVec3().InBounds(Find.CurrentMap) || !Find.CurrentMap.roofGrid.Roofed(loc.ToIntVec3())) && DebugViewSettings.drawShadows)
+ {
+ Vector3 position = loc + shadowData.offset;
+ position.y = AltitudeLayer.Shadows.AltitudeFor();
+ Graphics.DrawMesh(shadowMesh, position, rot.AsQuat, MatBases.SunShadowFade, 0);
+ }
+ }
+
+ public override void Print(SectionLayer layer, Thing thing, float extraRotation)
+ {
+
+ }
+
+ public override string ToString()
+ {
+ return $"Graphic_DynamicShadow({shadowData})";
+ }
+ }
+}
diff --git a/Source/Vehicles/Graphics/Graphic/Graphics/VanillaSupported/Graphic_RGB.cs b/Source/Vehicles/Graphics/Graphic/Graphics/Vehicle/Graphic_RGB.cs
similarity index 100%
rename from Source/Vehicles/Graphics/Graphic/Graphics/VanillaSupported/Graphic_RGB.cs
rename to Source/Vehicles/Graphics/Graphic/Graphics/Vehicle/Graphic_RGB.cs
diff --git a/Source/Vehicles/Graphics/Graphic/MaterialGeneration/RGBMaterialPool.cs b/Source/Vehicles/Graphics/Graphic/MaterialGeneration/RGBMaterialPool.cs
index 30c6089b..5fc2e688 100644
--- a/Source/Vehicles/Graphics/Graphic/MaterialGeneration/RGBMaterialPool.cs
+++ b/Source/Vehicles/Graphics/Graphic/MaterialGeneration/RGBMaterialPool.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -7,6 +8,10 @@
using Verse;
using SmashTools;
using Object = UnityEngine.Object;
+using RimWorld;
+using RimWorld.Planet;
+using Verse.AI;
+using Verse.Noise;
namespace Vehicles
{
@@ -39,7 +44,12 @@ public static Material Get(IMaterialCacheTarget target, Rot8 rot)
public static void CacheMaterialsFor(IMaterialCacheTarget target, int renderQueue = 0, List shaderParameters = null)
{
- if (cache.ContainsKey(target) || target.PatternDef == null)
+ CacheMaterialsFor(target, target.PatternDef, renderQueue: renderQueue, shaderParameters: shaderParameters);
+ }
+
+ public static void CacheMaterialsFor(IMaterialCacheTarget target, PatternDef patternDef, int renderQueue = 0, List shaderParameters = null)
+ {
+ if (cache.ContainsKey(target) || patternDef == null)
{
return;
}
@@ -48,7 +58,7 @@ public static void CacheMaterialsFor(IMaterialCacheTarget target, int renderQueu
for (int i = 0; i < materials.Length; i++)
{
Rot8 rot = new Rot8(i);
- Material material = new Material(target.PatternDef.ShaderTypeDef.Shader)
+ Material material = new Material(patternDef.ShaderTypeDef.Shader)
{
name = target.Name + rot.ToStringNamed(),
mainTexture = null,
@@ -168,6 +178,7 @@ public static void Release(IMaterialCacheTarget target)
}
cache.Remove(target);
+ GraphicDatabaseRGB.Remove(target);
Debug.Message($"{VehicleHarmony.LogLabel} Removed {target} from RGBMaterialPool and cleared all entries.");
}
}
@@ -185,5 +196,162 @@ internal static void LogAllMaterials()
Log.Message(report.ToString());
}
+
+ [UnitTest(Category = "Performance", Name = "Material Memory Management", GameState = GameState.Playing)]
+ private static void UnitTest_MaterialMemoryManagement()
+ {
+ LongEventHandler.ExecuteWhenFinished(delegate ()
+ {
+ CoroutineManager.QueueInvoke(TestVehicleMaterialCaching);
+ });
+ }
+
+ private static IEnumerator TestVehicleMaterialCaching()
+ {
+ Log.Message($"------ Running MaterialMemoryManagement Test ------ ");
+
+ Map map = Find.CurrentMap ?? Find.Maps.FirstOrDefault(map => map.Parent is Settlement settlement && settlement.Faction == Faction.OfPlayerSilentFail);
+ if (map == null)
+ {
+ Log.Error($"Unable to conduct material memory management unit test. Null map.");
+ yield break;
+ }
+
+ MaterialTesting materialTest = new MaterialTesting();
+
+ IntVec3 cell = map.Center;
+
+ materialTest.Start("Defs");
+ foreach (VehicleDef vehicleDef in DefDatabase.AllDefs)
+ {
+ materialTest.Start(vehicleDef.defName);
+ {
+ ClearAreaSpawnTerrain(vehicleDef, map, cell);
+
+ VehiclePawn generatedVehicle = VehicleSpawner.GenerateVehicle(vehicleDef, Faction.OfPlayer);
+ VehiclePawn vehicle = (VehiclePawn)GenSpawn.Spawn(generatedVehicle, cell, map, Rot8.North, WipeMode.FullRefund, false);
+ _ = vehicle.VehicleGraphic; //allow graphic to be cached before any upgrade calls
+
+ if (vehicle.CompUpgradeTree != null)
+ {
+ foreach (UpgradeNode node in vehicle.CompUpgradeTree.Props.def.nodes)
+ {
+ materialTest.Start($"{vehicleDef.defName} {vehicle.CompUpgradeTree.Props.def}->{node.key}");
+ {
+ vehicle.CompUpgradeTree.FinishUnlock(node);
+ yield return null; //1 frame for rendering
+ vehicle.CompUpgradeTree.ResetUnlock(node);
+ }
+ materialTest.Stop();
+ }
+ }
+ vehicle.Destroy();
+ }
+ materialTest.Stop();
+ yield return null;
+ }
+ materialTest.Stop();
+
+ Log.Message($"------ Report Complete ------ ");
+
+ if (materialTest.OngoingTests)
+ {
+ Log.Error($"Finished MaterialCache Report but material testing is still ongoing.");
+ }
+
+ }
+
+ private static void ClearAreaSpawnTerrain(VehicleDef vehicleDef, Map map, IntVec3 cell)
+ {
+ TerrainDef validTerrain = DefDatabase.AllDefsListForReading.Where(terrainDef => TerrainCostFor(vehicleDef, terrainDef) < VehiclePathGrid.ImpassableCost).RandomElement();
+
+ try
+ {
+ IntVec2 sizeNeeded = vehicleDef.Size;
+ for (int x = -sizeNeeded.x; x < sizeNeeded.x; x++)
+ {
+ for (int z = -sizeNeeded.z; z < sizeNeeded.z; z++)
+ {
+ IntVec3 rectCell = new IntVec3(cell.x + x, 0, cell.z + z);
+ List thingList = map.thingGrid.ThingsListAtFast(rectCell).ToList();
+ foreach (Thing thing in thingList)
+ {
+ thing.Destroy();
+ }
+ map.terrainGrid.SetTerrain(rectCell, validTerrain);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Exception thrown clearing area for {vehicleDef}.\nException={ex}");
+ }
+ }
+
+ private static int TerrainCostFor(VehicleDef vehicleDef, TerrainDef terrainDef)
+ {
+ if (vehicleDef.properties.customTerrainCosts.TryGetValue(terrainDef, out int pathCost))
+ {
+ return pathCost;
+ }
+ return terrainDef.pathCost;
+ }
+
+ private class MaterialTesting
+ {
+ private StringBuilder reportBuilder = new StringBuilder();
+ private Stack ongoingTests = new Stack();
+
+ public bool OngoingTests => ongoingTests.Count > 0;
+
+ public void Start(string label)
+ {
+ int targets = cache.Count;
+ int materials = cache.Values.Sum(arr => arr.Length);
+
+ this.ongoingTests.Push(new TestCase(label, targets, materials));
+ }
+
+ public void Stop()
+ {
+ reportBuilder.Clear();
+ int targetsAfter = cache.Count;
+ int materialsAfter = cache.Values.Sum(arr => arr.Length);
+
+ TestCase testCase = ongoingTests.Pop();
+
+ bool targetResult = testCase.targets == targetsAfter;
+ bool materialsResult = testCase.materials == materialsAfter;
+
+ reportBuilder.AppendLine($"[{testCase.label}]: Targets={ResultString(targetResult)} Materials={ResultString(materialsResult)}");
+ reportBuilder.AppendInNewLine($"Targets: {testCase.targets}->{targetsAfter} Materials: {testCase.materials}->{materialsAfter}");
+
+ SmashLog.Message(reportBuilder.ToString());
+ reportBuilder.Clear();
+ }
+
+ private string ResultString(bool value)
+ {
+ if (value)
+ {
+ return $"True";
+ }
+ return $"False";
+ }
+
+ private class TestCase
+ {
+ public string label;
+ public int targets;
+ public int materials;
+
+ public TestCase(string label, int targets, int materials)
+ {
+ this.label = label;
+ this.targets = targets;
+ this.materials = materials;
+ }
+ }
+ }
}
}
diff --git a/Source/Vehicles/Graphics/Graphic/Retexture/RetextureDef.cs b/Source/Vehicles/Graphics/Graphic/Retexture/RetextureDef.cs
index 2e9621bd..90dd9e07 100644
--- a/Source/Vehicles/Graphics/Graphic/Retexture/RetextureDef.cs
+++ b/Source/Vehicles/Graphics/Graphic/Retexture/RetextureDef.cs
@@ -9,11 +9,8 @@ public class RetextureDef : Def
{
public GraphicDataRGB graphicData;
-#pragma warning disable IDE0044 // Add readonly modifier
- private VehicleDef vehicle = null;
-#pragma warning restore IDE0044 // Add readonly modifier
-
- public List factions = new List();
+ //TODO - Add faction specific retextures available for NPC generation
+ //public List factions = new List();
public override IEnumerable ConfigErrors()
{
@@ -21,15 +18,11 @@ public override IEnumerable ConfigErrors()
{
yield return error;
}
- if (vehicle is null)
- {
- yield return "vehicle must be specified for a valid retexture.".ConvertRichText();
- }
}
public override void ResolveReferences()
{
- factions ??= new List();
+ //factions ??= new List();
}
}
}
diff --git a/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Passengers.cs b/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Passengers.cs
index 75feccc6..482fe5ed 100644
--- a/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Passengers.cs
+++ b/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Passengers.cs
@@ -113,7 +113,7 @@ protected override void ExtraOnGUI()
return;
}
Rect rendererRect = new Rect(0, 0, pawnOverlayRect.width, pawnOverlayRect.height).ContractedBy(5);
- editingPawnOverlayRenderer.role.pawnRenderer.RenderEditor(rendererRect);
+ editingPawnOverlayRenderer.role.PawnRenderer.RenderEditor(rendererRect);
if (Widgets.CloseButtonFor(rendererRect))
{
editingPawnOverlayRenderer = null;
diff --git a/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Upgrades.cs b/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Upgrades.cs
index 3ea35d63..62687869 100644
--- a/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Upgrades.cs
+++ b/Source/Vehicles/Graphics/ITab/ITab_Vehicle_Upgrades.cs
@@ -26,13 +26,15 @@ public class ITab_Vehicle_Upgrades : ITab
public const float ScreenWidth = 880f;
public const float ScreenHeight = 520f;
- public const float InfoScreenWidth = 325;
+ public const float InfoSummaryWidth = 300;
+ public const float InfoScreenWidth = 375;
public const float InfoScreenHeight = 150;
- public const float InfoScreenExtraGUIHeight = InfoScreenHeight;
public const float InfoPanelRowHeight = 20f;
public const float InfoPanelMoreDetailButtonSize = 24;
public const float InfoPanelArrowPointerSize = 45;
+ public const float OverlayGraphicHeight = (InfoScreenWidth - InfoPanelArrowPointerSize) / 2;
+
public const float BottomWindowEdge = ScreenHeight - TopPadding * 2;
public const float TotalIconSizeScalar = 6000f;
@@ -44,6 +46,10 @@ public class ITab_Vehicle_Upgrades : ITab
public static readonly Color DisabledColor = new Color(0.25f, 0.25f, 0.25f, 1);
public static readonly Color DisabledLineColor = new Color(0.3f, 0.3f, 0.3f, 1);
+ public static readonly Color EffectColorPositive = new Color(0.1f, 1f, 0.1f);
+ public static readonly Color EffectColorNegative = new Color(0.8f, 0.4f, 0.4f);
+ public static readonly Color EffectColorNeutral = new Color(0.5f, 0.5f, 0.5f, 0.75f);
+
public static readonly Vector2 GridSpacing = new Vector2(20, 20);
public static readonly Vector2 GridOrigin = new Vector2(30, 30);
@@ -54,12 +60,16 @@ public class ITab_Vehicle_Upgrades : ITab
private UpgradeNode selectedNode;
private UpgradeNode highlightedNode;
+ private List textEntries = new List();
+ private float textEntryHeight;
+
+ private List renderTurrets = new List();
+ private List excludeTurrets = new List();
- private Rect detailRect;
- private bool moreDetail = false;
+ private bool showDetails;
- private static Vector2 scrollPosition;
- private static Vector2 resize;
+ private Vector2 scrollPosition;
+ private Vector2 resize;
private bool resizeCheck;
public UpgradeNode InfoNode => selectedNode ?? highlightedNode;
@@ -74,8 +84,15 @@ public UpgradeNode SelectedNode
{
if (selectedNode != value)
{
+ ClearTurretRenderers(selectedNode);
+
selectedNode = value;
- moreDetail = false;
+
+ if (selectedNode != null)
+ {
+ RecacheTextEntries();
+ RecacheTurretRenderers();
+ }
}
}
}
@@ -116,8 +133,9 @@ private VehiclePawn Vehicle
if (SelPawn is null)
{
return null;
- }
- throw new InvalidOperationException("Upgrade ITab on Pawn without CompUpgradeTree: " + SelThing);
+ }
+ CloseTab();
+ return null;
}
}
@@ -130,6 +148,74 @@ public override void OnOpen()
scrollPosition = Vector2.zero;
}
+ private void RecacheTextEntries()
+ {
+ textEntries.Clear();
+ return;
+ if (SelectedNode != null && SelectedNode.upgradeExplanation != null)
+ {
+ textEntryHeight = Text.CalcHeight(SelectedNode.upgradeExplanation, InfoScreenWidth - 10);
+ }
+ else
+ {
+ foreach (Upgrade upgrade in InfoNode.upgrades)
+ {
+ foreach (UpgradeTextEntry textEntry in upgrade.UpgradeDescription(Vehicle))
+ {
+ textEntries.Add(textEntry);
+ }
+ }
+ textEntryHeight = textEntries.Count * InfoPanelRowHeight;
+ }
+ }
+
+ private void RecacheTurretRenderers()
+ {
+ if (!SelectedNode.upgrades.NullOrEmpty())
+ {
+ foreach (Upgrade upgrade in InfoNode.upgrades)
+ {
+ if (upgrade is TurretUpgrade turretUpgrade)
+ {
+ if (!turretUpgrade.turrets.NullOrEmpty())
+ {
+ foreach (VehicleTurret turret in turretUpgrade.turrets)
+ {
+ turret.ResolveCannonGraphics(Vehicle.VehicleDef, forceRegen: true);
+ renderTurrets.Add(turret);
+ }
+ }
+ if (!turretUpgrade.removeTurrets.NullOrEmpty())
+ {
+ excludeTurrets.AddRange(turretUpgrade.removeTurrets);
+ }
+ }
+ }
+ }
+ }
+
+ private void ClearTurretRenderers(UpgradeNode upgradeNode)
+ {
+ if (upgradeNode != null && !upgradeNode.upgrades.NullOrEmpty())
+ {
+ foreach (Upgrade upgrade in InfoNode.upgrades)
+ {
+ if (upgrade is TurretUpgrade turretUpgrade)
+ {
+ if (!turretUpgrade.turrets.NullOrEmpty())
+ {
+ foreach (VehicleTurret turret in turretUpgrade.turrets)
+ {
+ turret.OnDestroy();
+ }
+ }
+ }
+ }
+ }
+ renderTurrets.Clear();
+ excludeTurrets.Clear();
+ }
+
private Vector2 GridCoordinateToScreenPos(IntVec2 coord)
{
float x = GridOrigin.x + (GridSpacing.x * coord.x) - (GridSpacing.x / 2);
@@ -150,6 +236,12 @@ private Vector2 GridCoordinateToScreenPosAdjusted(IntVec2 coord, Vector2 drawSiz
protected override void FillTab()
{
+ //May occur if sub-window is open while selected entity changes inbetween frames
+ if (Vehicle == null)
+ {
+ return;
+ }
+
Rect rect = new Rect(0f, TopPadding, size.x, size.y - TopPadding);
Rect innerRect = rect.ContractedBy(5f);
@@ -353,150 +445,210 @@ private void DrawGrid(Rect rect)
}
}
- float maxedInfoScreenHeight = InfoScreenHeight;
+ GUIState.Reset();
+
+ Rect selectedLabelRect = new Rect(5f, BottomWindowEdge, ScreenWidth, 150f);
+
if (InfoNode != null)
{
- Vector2 upgradeRectPos = GridCoordinateToScreenPosAdjusted(InfoNode.GridCoordinate, InfoNode.drawSize);
- Rect upgradeRect = new Rect(upgradeRectPos, InfoNode.drawSize);
-
- float ingredientsHeight = 0;
- if (!InfoNode.ingredients.NullOrEmpty())
+ Rect detailRect = GetDetailRect(rect);
+ //detailRect.position += TabRect.position;
+ Widgets.BeginGroup(detailRect);
{
- ingredientsHeight = InfoNode.ingredients.Count * InfoPanelRowHeight;
+ Rect infoPanelRect = detailRect.AtZero();
+ DrawInfoPanel(infoPanelRect);
}
+ Widgets.EndGroup();
+ //Find.WindowStack.ImmediateWindow(InfoNode.GetHashCode() ^ Vehicle.GetHashCode(), detailRect, WindowLayer.GameUI, delegate ()
+ //{
+ // if (Vehicle != null && InfoNode != null)
+ // {
+ // Rect infoPanelRect = detailRect.AtZero();
+ // DrawInfoPanel(infoPanelRect);
+ // }
+ //}, doBackground: false);
+ }
- float textHeight = Text.CalcHeight(InfoNode.label, InfoScreenWidth) + Text.CalcHeight(InfoNode.description, InfoScreenWidth);
- maxedInfoScreenHeight = Mathf.Max(InfoScreenHeight, textHeight) + ingredientsHeight;
+ //Widgets.EndScrollView();
- float infoScreenX = upgradeRect.x + InfoNode.drawSize.x / 2f - InfoScreenWidth / 2f;
- float windowRectX = Mathf.Clamp(infoScreenX, rect.x + 5, Screen.width - InfoScreenWidth - 5);
+ GUIState.Pop();
+ }
- float windowRectY = upgradeRect.yMax + 5f;
- if (windowRectY + maxedInfoScreenHeight >= ScreenHeight)
- {
- windowRectY -= maxedInfoScreenHeight + 10f + InfoNode.drawSize.y;
- }
+ private Rect GetDetailRect(Rect rect, float padding = 5)
+ {
+ GUIState.Push();
- detailRect = new Rect(windowRectX, windowRectY, InfoScreenWidth, maxedInfoScreenHeight);
- }
+ Vector2 upgradeRectPos = GridCoordinateToScreenPosAdjusted(InfoNode.GridCoordinate, InfoNode.drawSize);
+ Rect upgradeRect = new Rect(upgradeRectPos, InfoNode.drawSize);
- GUIState.Reset();
+ float ingredientsHeight = 0;
+ if (!InfoNode.ingredients.NullOrEmpty())
+ {
+ ingredientsHeight = InfoNode.ingredients.Count * InfoPanelRowHeight;
+ }
- Rect selectedLabelRect = new Rect(5f, BottomWindowEdge, ScreenWidth, 150f);
+ float detailWidth = InfoScreenWidth - padding * 2;
+ if (SelectedNode != null)
+ {
+ //detailWidth = InfoScreenWidth - padding * 2;
+ }
- if (InfoNode != null)
+ Text.Font = GameFont.Medium;
+ float labelHeight = Text.CalcHeight(InfoNode.label, detailWidth);
+ Text.Font = GameFont.Small;
+ float descriptionHeight = Text.CalcHeight(InfoNode.description, detailWidth);
+ float totalCalculatedHeight = labelHeight + descriptionHeight + ingredientsHeight + 30 + padding;
+ if (SelectedNode != null)
{
- Rect infoRect = new Rect(TabRect.x + detailRect.x, TabRect.y + detailRect.y, detailRect.width, detailRect.height);
- Find.WindowStack.ImmediateWindow(InfoNode.GetHashCode(), infoRect, WindowLayer.SubSuper, delegate ()
+ totalCalculatedHeight += 10; //5 padding from description to line, and line to bottom rect
+ if (SelectedNode.HasGraphics)
{
- if (Vehicle != null && InfoNode != null)
- {
- GUIState.Push();
+ totalCalculatedHeight += OverlayGraphicHeight;
+ }
+
+ if (!textEntries.NullOrEmpty())
+ {
+ totalCalculatedHeight += textEntryHeight + 5;
+ }
+ }
+
+ float windowRectX = upgradeRect.x + InfoNode.drawSize.x + padding;
+ if (windowRectX + detailWidth > rect.xMax - padding)
+ {
+ windowRectX = upgradeRect.x - detailWidth - padding;
+ windowRectX = Mathf.Clamp(windowRectX, rect.x + padding, rect.xMax - detailWidth - padding);
+ }
- Rect menuRect = new Rect(0, 0, infoRect.width, infoRect.height);
- Widgets.DrawMenuSection(menuRect);
-
- Rect innerInfoRect = menuRect.ContractedBy(5);
+ float maxInfoScreenHeight = Mathf.Max(InfoScreenHeight, totalCalculatedHeight);
+ float windowRectY = upgradeRect.y + InfoNode.drawSize.y / 2 - maxInfoScreenHeight / 2;
+ windowRectY = Mathf.Clamp(windowRectY, rect.y + padding, rect.yMax - maxInfoScreenHeight - padding);
- Rect moreDetailRect = new Rect(innerInfoRect.xMax - InfoPanelMoreDetailButtonSize, innerInfoRect.y, InfoPanelMoreDetailButtonSize, InfoPanelMoreDetailButtonSize);
+ //if (windowRectY + maxInfoScreenHeight >= ScreenHeight)
+ //{
+ // windowRectY -= maxInfoScreenHeight + padding * 2 + InfoNode.drawSize.y;
+ //}
- Color baseColor = !moreDetail ? Color.white : Color.green;
- Color mouseoverColor = !moreDetail ? GenUI.MouseoverColor : new Color(0f, 0.5f, 0f);
- if (!InfoNode.graphicOverlays.NullOrEmpty() && Widgets.ButtonImageFitted(moreDetailRect, CaravanThingsTabUtility.SpecificTabButtonTex, baseColor, mouseoverColor))
- {
- moreDetail = !moreDetail;
+ GUIState.Pop();
+ return new Rect(windowRectX, windowRectY, detailWidth, maxInfoScreenHeight);
+ }
- if (moreDetail)
- {
- SoundDefOf.TabOpen.PlayOneShotOnCamera(null);
- }
- else
- {
- SoundDefOf.TabClose.PlayOneShotOnCamera(null);
- }
- }
- GUIState.Reset();
+ private void DrawInfoPanel(Rect rect, float padding = 5)
+ {
+ GUIState.Push();
- Rect detailRect = innerInfoRect;
- Text.Font = GameFont.Medium;
- float textHeight = Text.CalcHeight(InfoNode.label, detailRect.width);
- Rect labelRect = new Rect(detailRect.x, detailRect.y, detailRect.width, textHeight);
- Widgets.Label(labelRect, InfoNode.label);
+ Widgets.DrawMenuSection(rect);
- detailRect.y += textHeight;
- detailRect.height -= textHeight;
+ Rect innerInfoRect = rect.ContractedBy(padding);
- Text.Font = GameFont.Small;
+ GUIState.Reset();
- float costY = DrawCostItems(detailRect);
+ Text.Font = GameFont.Medium;
- detailRect.y += costY;
- detailRect.height -= costY + 30;
+ float labelHeight = Text.CalcHeight(InfoNode.label, innerInfoRect.width);
+ Rect labelRect = new Rect(innerInfoRect.x, innerInfoRect.y, innerInfoRect.width, labelHeight);
+ Widgets.Label(labelRect, InfoNode.label);
- Widgets.Label(detailRect, InfoNode.description);
+ Text.Font = GameFont.Small;
- if (Vehicle.CompUpgradeTree.NodeUnlocking == InfoNode)
- {
- textHeight = Text.CalcHeight(InfoNode.description, detailRect.width);
- detailRect.y += textHeight;
- detailRect.height -= textHeight;
+ Rect costListRect = new Rect(innerInfoRect.x, labelRect.yMax, innerInfoRect.width, innerInfoRect.height - labelRect.height);
+ float costY = DrawCostItems(costListRect);
+ Rect tempRect = costListRect;
+ tempRect.height = costY;
- string workLabel = $"{"WorkLeft".Translate()}: {Vehicle.CompUpgradeTree.upgrade.WorkLeft.ToStringWorkAmount()}";
- textHeight = Text.CalcHeight(workLabel, detailRect.width);
- Rect workLabelRect = new Rect(detailRect.x, detailRect.y, detailRect.width, textHeight);
- Widgets.Label(workLabelRect, workLabel);
+ float descriptionHeight = Text.CalcHeight(InfoNode.description, innerInfoRect.width);
+ Rect descriptionRect = new Rect(innerInfoRect.x, costListRect.y + costY, innerInfoRect.width, descriptionHeight);
+ Widgets.Label(descriptionRect, InfoNode.description);
+
+ if (Vehicle.CompUpgradeTree.NodeUnlocking == InfoNode)
+ {
+ //string workLabel = $"{"WorkLeft".Translate()}: {Vehicle.CompUpgradeTree.upgrade.WorkLeft.ToStringWorkAmount()}";
+ //textHeight = Text.CalcHeight(workLabel, upgradeInfoRect.width);
+ //Rect workLabelRect = new Rect(upgradeInfoRect.x, upgradeInfoRect.y, upgradeInfoRect.width, textHeight);
+ //Widgets.Label(workLabelRect, workLabel);
- detailRect.y += textHeight;
- detailRect.height -= textHeight;
- }
+ //upgradeInfoRect.y += textHeight;
+ //upgradeInfoRect.height -= textHeight;
+ }
- if (SelectedNode != null)
- {
- Rect buttonRect = new Rect(detailRect.xMax - 125f, menuRect.yMax - 35, 120, 30);
- DrawButtons(buttonRect);
- }
+ if (SelectedNode != null)
+ {
+ bool hasGraphics = SelectedNode.HasGraphics;
+ bool showUpgradeList = false; //!SelectedNode.upgrades.NullOrEmpty();
- GUIState.Pop();
- }
- }, doBackground: false);
+ if (hasGraphics || showUpgradeList)
+ {
+ Widgets.DrawLineHorizontal(rect.x, descriptionRect.yMax + 5, rect.width, UIElements.MenuSectionBGBorderColor);
+ }
- if (moreDetail)
+ Rect textEntryRect = new Rect(innerInfoRect.x, descriptionRect.yMax + 10, innerInfoRect.width, textEntryHeight);
+ if (showUpgradeList)
{
- float infoScreenExtraGUIWidth = InfoScreenExtraGUIHeight * 2 + InfoPanelArrowPointerSize;
- float heightDifference = (maxedInfoScreenHeight - InfoScreenHeight) / 2;
- Rect moreDetailRect = new Rect(TabRect.x + detailRect.xMax + 5, TabRect.y + detailRect.y + heightDifference, infoScreenExtraGUIWidth, InfoScreenExtraGUIHeight);
- Find.WindowStack.ImmediateWindow(InfoNode.GetHashCode() ^ Vehicle.GetHashCode(), moreDetailRect, WindowLayer.SubSuper, delegate ()
- {
- if (Vehicle != null && InfoNode != null)
- {
- GUIState.Push();
+ DrawUpgradeList(textEntryRect);
+ }
- Rect menuRect = new Rect(0, 0, moreDetailRect.width, moreDetailRect.height);
- Widgets.DrawMenuSection(menuRect);
+ if (hasGraphics)
+ {
+ Rect overlayShowcaseRect = new Rect(innerInfoRect.x, textEntryRect.yMax + 5, innerInfoRect.width, (innerInfoRect.width - InfoPanelArrowPointerSize) / 2);
+ DrawVehicleGraphicComparison(overlayShowcaseRect);
+ }
- Rect innerInfoRect = menuRect.ContractedBy(5);
+ Rect buttonRect = new Rect(innerInfoRect.xMax - 125f, innerInfoRect.yMax - 30, 120, 30);
+ DrawButtons(buttonRect);
- Rect vehicleOriginalRect = new Rect(innerInfoRect.x, innerInfoRect.y, innerInfoRect.height, innerInfoRect.height);
- VehicleGraphics.DrawVehicle(vehicleOriginalRect, Vehicle);
+ Rect tempButtonRect = buttonRect;
+ tempButtonRect.width = innerInfoRect.width;
- float arrowSize = InfoPanelArrowPointerSize;
- Rect arrowPointerRect = new Rect(vehicleOriginalRect.xMax + 5, vehicleOriginalRect.y + vehicleOriginalRect.height / 2 - arrowSize / 2, arrowSize, arrowSize);
- Widgets.DrawTextureFitted(arrowPointerRect, TexData.TutorArrowRight, 1);
+ }
- Rect vehicleNewRect = new Rect(arrowPointerRect.xMax + 5, vehicleOriginalRect.y, vehicleOriginalRect.width, vehicleOriginalRect.height);
- VehicleGraphics.DrawVehicle(vehicleNewRect, Vehicle, extraOverlays: Vehicle.CompUpgradeTree.Props.TryGetOverlays(InfoNode));
+ GUIState.Pop();
+ }
- GUIState.Pop();
- }
- }, doBackground: false);
- }
- }
+ private void DrawVehicleGraphicComparison(Rect rect)
+ {
+ GUIState.Push();
- //Widgets.EndScrollView();
+ Rect innerInfoRect = rect.ContractedBy(5);
+
+ Rect vehicleOriginalRect = new Rect(innerInfoRect.x, innerInfoRect.y, innerInfoRect.height, innerInfoRect.height);
+ VehicleGraphics.DrawVehicle(vehicleOriginalRect, Vehicle);
+
+ float arrowSize = InfoPanelArrowPointerSize;
+ Rect arrowPointerRect = new Rect(vehicleOriginalRect.xMax + 5, vehicleOriginalRect.y + vehicleOriginalRect.height / 2 - arrowSize / 2, arrowSize, arrowSize);
+ Widgets.DrawTextureFitted(arrowPointerRect, TexData.TutorArrowRight, 1);
+
+ Rect vehicleNewRect = new Rect(arrowPointerRect.xMax + 5, vehicleOriginalRect.y, vehicleOriginalRect.width, vehicleOriginalRect.height);
+ VehicleGraphics.DrawVehicle(vehicleNewRect, Vehicle, extraOverlays: Vehicle.CompUpgradeTree.Props.TryGetOverlays(InfoNode), extraTurrets: renderTurrets, excludeTurrets: excludeTurrets);
GUIState.Pop();
}
+ private void DrawSubIconsBar(Rect rect)
+ {
+ Rect subIconsRect = new Rect(rect.xMax - InfoPanelMoreDetailButtonSize, rect.y, rect.width, InfoPanelMoreDetailButtonSize);
+
+ Color baseColor = !showDetails ? Color.white : Color.green;
+ Color mouseoverColor = !showDetails ? GenUI.MouseoverColor : new Color(0f, 0.5f, 0f);
+
+ Rect buttonRect = new Rect(subIconsRect.x, subIconsRect.y, InfoPanelMoreDetailButtonSize, InfoPanelMoreDetailButtonSize);
+ if (!InfoNode.upgrades.NullOrEmpty())
+ {
+ if (Widgets.ButtonImageFitted(buttonRect, TexButton.Info, baseColor, mouseoverColor))
+ {
+ showDetails = !showDetails;
+
+ if (showDetails)
+ {
+ SoundDefOf.TabOpen.PlayOneShotOnCamera(null);
+ }
+ else
+ {
+ SoundDefOf.TabClose.PlayOneShotOnCamera(null);
+ }
+ }
+ buttonRect.x -= buttonRect.width;
+ }
+ }
+
protected override void UpdateSize()
{
base.UpdateSize();
@@ -572,6 +724,53 @@ private float DrawCostItems(Rect rect)
return currentY;
}
+ private void DrawUpgradeList(Rect rect)
+ {
+ GUIState.Push();
+ if (InfoNode.upgradeExplanation != null)
+ {
+ Widgets.Label(rect, InfoNode.upgradeExplanation);
+ }
+ else if (!InfoNode.upgrades.NullOrEmpty())
+ {
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ //Lists upgrade details if none is included
+ foreach (Upgrade upgrade in InfoNode.upgrades)
+ {
+ foreach (UpgradeTextEntry textEntry in upgrade.UpgradeDescription(Vehicle))
+ {
+ float labelWidth = rect.width * 0.75f;
+ float labelHeight = Text.CalcHeight(textEntry.label, labelWidth);
+ float valueWidth = rect.width - labelWidth;
+ float valueHeight = Text.CalcHeight(textEntry.description, valueWidth);
+
+ float entryHeight = Mathf.Max(labelHeight, valueHeight);
+
+ Rect leftRect = new Rect(rect.x, rect.y, labelWidth, entryHeight);
+ Widgets.Label(leftRect, textEntry.label);
+
+ GUI.color = textEntry.effectType switch
+ {
+ UpgradeEffectType.Positive => EffectColorPositive,
+ UpgradeEffectType.Negative => EffectColorNegative,
+ UpgradeEffectType.Neutral => EffectColorNeutral,
+ UpgradeEffectType.None => Color.white,
+ _ => Color.white,
+ };
+
+ Rect rightRect = new Rect(leftRect.xMax, rect.y, valueWidth, entryHeight);
+ Widgets.Label(rightRect, textEntry.description);
+
+ rect.y += entryHeight;
+
+ GUIState.Reset();
+ }
+ }
+ }
+ GUIState.Pop();
+ }
+
private void DrawNodeCondition(Rect rect, UpgradeNode node, bool colored)
{
if (DisabledAndMouseOver())
diff --git a/Source/Vehicles/Graphics/Listing/Listing_Settings.cs b/Source/Vehicles/Graphics/Listing/Listing_Settings.cs
index 8023f413..edf3c7de 100644
--- a/Source/Vehicles/Graphics/Listing/Listing_Settings.cs
+++ b/Source/Vehicles/Graphics/Listing/Listing_Settings.cs
@@ -174,7 +174,6 @@ public void IntegerBox(VehicleDef def, SaveableField field, string label, string
Rect rectLeft = new Rect(rect.x, centerY, leftLength, rect.height);
Rect rectRight = new Rect(rect.x + rect.width - rightLength, centerY, rightLength, Text.LineHeight);
- Color color = GUI.color;
bool mouseOver = Mouse.IsOver(rect);
if (disabled)
{
@@ -213,7 +212,7 @@ public void IntegerBox(VehicleDef def, SaveableField field, string label, string
}
Widgets.Label(rectLeft, label);
- Text.CurTextFieldStyle.alignment = TextAnchor.MiddleRight;
+ Text.Anchor = TextAnchor.MiddleRight;
string buffer = value.ToString();
int valueBefore = value;
Widgets.TextFieldNumeric(rectRight, ref value, ref buffer, min, max);
@@ -287,7 +286,7 @@ public void FloatBox(VehicleDef def, SaveableField field, string label, string t
}
Widgets.Label(rectLeft, label);
- Text.CurTextFieldStyle.alignment = TextAnchor.MiddleRight;
+ Text.Anchor = TextAnchor.MiddleRight;
string buffer = value.ToString();
float valueBefore = value;
Widgets.TextFieldNumeric(rectRight, ref value, ref buffer, min, max);
diff --git a/Source/Vehicles/Graphics/Misc/TransferableVehicleWidget.cs b/Source/Vehicles/Graphics/Misc/TransferableVehicleWidget.cs
index a518ed55..bb1573d9 100644
--- a/Source/Vehicles/Graphics/Misc/TransferableVehicleWidget.cs
+++ b/Source/Vehicles/Graphics/Misc/TransferableVehicleWidget.cs
@@ -142,7 +142,7 @@ public void AddSection(string title, IEnumerable transferabl
if (!transferables.EnumerableNullOrEmpty())
{
- WorldVehiclePathGrid worldVehiclePathGrid = Find.World.GetCachedWorldComponent();
+ WorldVehiclePathGrid worldVehiclePathGrid = Find.World.GetComponent();
foreach (TransferableOneWay transferable in transferables)
{
if (transferable.AnyThing is VehiclePawn vehicle)
diff --git a/Source/Vehicles/Harmony/ConditionalPatches/Compatibility_RoadsOfTheRim.cs b/Source/Vehicles/Harmony/ConditionalPatches/Compatibility_RoadsOfTheRim.cs
index a8d424a9..6cd92a59 100644
--- a/Source/Vehicles/Harmony/ConditionalPatches/Compatibility_RoadsOfTheRim.cs
+++ b/Source/Vehicles/Harmony/ConditionalPatches/Compatibility_RoadsOfTheRim.cs
@@ -20,7 +20,7 @@ internal class Compatibility_RoadsOfTheRim : ConditionalVehiclePatch
public override void PatchAll(ModMetaData mod, Harmony harmony)
{
- Type alertClassType = AccessTools.TypeByName("RoadsOfTheRim.Patch_Alert_CaravanIdle_GetReport");
+ Type alertClassType = AccessTools.TypeByName("RoadsOfTheRim.HarmonyPatches.Alert_CaravanIdle_GetReport");
harmony.Patch(original: AccessTools.Method(alertClassType, "Postfix"),
transpiler: new HarmonyMethod(typeof(Compatibility_RoadsOfTheRim),
nameof(GetAlertReportIdleConstructionVehicle)));
diff --git a/Source/Vehicles/Harmony/DebugProperties.cs b/Source/Vehicles/Harmony/DebugProperties.cs
new file mode 100644
index 00000000..730dd8bb
--- /dev/null
+++ b/Source/Vehicles/Harmony/DebugProperties.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Vehicles
+{
+ public static class DebugProperties
+ {
+ public static readonly bool debug = false;
+
+ public static readonly bool drawPaths = false;
+ }
+}
diff --git a/Source/Vehicles/Harmony/PatchCategories/CaravanHandling.cs b/Source/Vehicles/Harmony/PatchCategories/CaravanHandling.cs
index 3c7eb3bf..c025751f 100644
--- a/Source/Vehicles/Harmony/PatchCategories/CaravanHandling.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/CaravanHandling.cs
@@ -752,7 +752,7 @@ public static List InternalPawnsIncludedInList(List __result, Carava
{
tmpCaravanPawns.Clear();
tmpCaravanPawns.AddRange(__result);
- foreach (VehiclePawn vehicle in vehicleCaravan.Vehicles)
+ foreach (VehiclePawn vehicle in vehicleCaravan.VehiclesListForReading)
{
tmpCaravanPawns.AddRange(vehicle.AllPawnsAboard);
}
diff --git a/Source/Vehicles/Harmony/PatchCategories/Debug.cs b/Source/Vehicles/Harmony/PatchCategories/Debug.cs
index 87455d66..37b2c729 100644
--- a/Source/Vehicles/Harmony/PatchCategories/Debug.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/Debug.cs
@@ -12,6 +12,7 @@
using RimWorld.Planet;
using LudeonTK;
using SmashTools;
+using static UnityEngine.Scripting.GarbageCollector;
namespace Vehicles
{
@@ -43,7 +44,11 @@ public static void Error(string text)
public void PatchMethods()
{
- if (VehicleHarmony.debug)
+ VehicleHarmony.Patch(original: AccessTools.Method(typeof(DebugToolsSpawning), "SpawnPawn"),
+ postfix: new HarmonyMethod(typeof(Debug),
+ nameof(DebugHideVehiclesFromPawnSpawner)));
+
+ if (DebugProperties.debug)
{
//VehicleHarmony.Patch(original: AccessTools.Method(typeof(WorldRoutePlanner), nameof(WorldRoutePlanner.WorldRoutePlannerUpdate)), prefix: null,
// postfix: new HarmonyMethod(typeof(Debug),
@@ -53,10 +58,7 @@ public void PatchMethods()
// nameof(DebugWorldObjects)));
}
- VehicleHarmony.Patch(original: AccessTools.Method(typeof(DebugToolsSpawning), "SpawnPawn"),
- postfix: new HarmonyMethod(typeof(Debug),
- nameof(DebugHideVehiclesFromPawnSpawner)));
- //VehicleHarmony.Patch(original: AccessTools.Method(typeof(Caravan_NeedsTracker), "TrySatisfyPawnNeeds", parameters: new Type[] { typeof(Pawn) }),
+ //VehicleHarmony.Patch(original: AccessTools.Method(typeof(FloodFillerFog), nameof(FloodFillerFog.FloodUnfog)),
// prefix: new HarmonyMethod(typeof(Debug),
// nameof(TestPrefix)));
//VehicleHarmony.Patch(original: AccessTools.Method(typeof(XmlInheritance), nameof(XmlInheritance.TryRegister)),
@@ -65,13 +67,22 @@ public void PatchMethods()
//VehicleHarmony.Patch(original: AccessTools.Method(typeof(Thing), "ExposeData"),
// finalizer: new HarmonyMethod(typeof(Debug),
// nameof(ExceptionCatcher)));
+
+ //Type modType = AccessTools.TypeByName("SaveOurShip2.TEMPStopRedErrorOnTakeoff");
+
+ //VehicleHarmony.Harmony.Unpatch(original: AccessTools.Method(modType, "Prefix"), HarmonyPatchType.Prefix);
+ //VehicleHarmony.Harmony.Unpatch(original: AccessTools.Method(modType, "Postfix"), HarmonyPatchType.Postfix);
+
+ //VehicleHarmony.Patch(original: AccessTools.Method(modType, "Postfix"),
+ // prefix: new HarmonyMethod(typeof(Debug),
+ // nameof(TestModPatch)));
}
- public static void TestPrefix(Pawn pawn)
+ private static void TestPrefix(IntVec3 root)
{
try
{
- Log.Message($"Satisfying: {pawn}");
+ Log.Message($"Floodfilling map at {root}");
}
catch (Exception ex)
{
@@ -79,7 +90,7 @@ public static void TestPrefix(Pawn pawn)
}
}
- public static void TestPostfix(XmlNode node, ModContentPack mod)
+ private static void TestPostfix(XmlNode node, ModContentPack mod)
{
try
{
@@ -95,7 +106,7 @@ public static void TestPostfix(XmlNode node, ModContentPack mod)
}
}
- public static Exception ExceptionCatcher(Thing __instance, Exception __exception)
+ private static Exception ExceptionCatcher(Thing __instance, Exception __exception)
{
if (__exception != null)
{
@@ -108,11 +119,11 @@ public static Exception ExceptionCatcher(Thing __instance, Exception __exception
/// Show original settlement positions before being moved to the coast
///
///
- public static void DebugWorldObjects(WorldObject o)
+ private static void DebugWorldObjects(WorldObject o)
{
if(o is Settlement)
{
- VehicleHarmony.tiles.Add(new Pair(o.Tile, 0));
+ DebugHelper.tiles.Add(new Pair(o.Tile, 0));
}
}
@@ -120,7 +131,7 @@ public static void DebugWorldObjects(WorldObject o)
/// Removes Vehicle entries from Spawn Pawn menu, as that uses vanilla Pawn Generation whereas vehicles need special handling
///
///
- public static void DebugHideVehiclesFromPawnSpawner(List __result)
+ private static void DebugHideVehiclesFromPawnSpawner(List __result)
{
for (int i = __result.Count - 1; i >= 0; i--)
{
@@ -136,27 +147,27 @@ public static void DebugHideVehiclesFromPawnSpawner(List __resu
///
/// Draw paths from original settlement position to new position when moving settlement to coastline
///
- public static void DebugSettlementPaths()
+ private static void DebugSettlementPaths()
{
- if (VehicleHarmony.drawPaths && VehicleHarmony.debugLines.NullOrEmpty())
+ if (DebugProperties.drawPaths && DebugHelper.debugLines.NullOrEmpty())
{
return;
}
- if (VehicleHarmony.drawPaths)
+ if (DebugProperties.drawPaths)
{
- foreach (WorldPath wp in VehicleHarmony.debugLines)
+ foreach (WorldPath wp in DebugHelper.debugLines)
{
wp.DrawPath(null);
}
}
- foreach (Pair t in VehicleHarmony.tiles)
+ foreach (Pair t in DebugHelper.tiles)
{
GenDraw.DrawWorldRadiusRing(t.First, t.Second);
}
}
[DebugAction(VehicleHarmony.VehiclesLabel, "Draw Hitbox Size", allowedGameStates = AllowedGameStates.PlayingOnMap)]
- public static void DebugDrawHitbox()
+ private static void DebugDrawHitbox()
{
DebugTool tool = null;
IntVec3 first;
@@ -182,13 +193,13 @@ public static void DebugDrawHitbox()
}
[DebugAction(VehicleHarmony.VehiclesLabel, "Regenerate WorldPathGrid", allowedGameStates = AllowedGameStates.WorldRenderedNow)]
- public static void DebugRegenerateWorldPathGrid()
+ private static void DebugRegenerateWorldPathGrid()
{
- Find.World.GetCachedWorldComponent().RecalculateAllPerceivedPathCosts();
+ Find.World.GetComponent().RecalculateAllPerceivedPathCosts();
}
[DebugAction(VehicleHarmony.VehiclesLabel, "Ground All Aerial Vehicles", allowedGameStates = AllowedGameStates.Playing)]
- public static void DebugGroundAllAerialVehicles()
+ private static void DebugGroundAllAerialVehicles()
{
foreach (AerialVehicleInFlight aerialVehicle in VehicleWorldObjectsHolder.Instance.AerialVehicles)
{
diff --git a/Source/Vehicles/Harmony/PatchCategories/DefGenerators/ThingDefGenerator_Buildables.cs b/Source/Vehicles/Harmony/PatchCategories/DefGenerators/ThingDefGenerator_Buildables.cs
index 5de6dc0d..69383cb4 100644
--- a/Source/Vehicles/Harmony/PatchCategories/DefGenerators/ThingDefGenerator_Buildables.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/DefGenerators/ThingDefGenerator_Buildables.cs
@@ -17,7 +17,7 @@ public static bool GenerateImpliedBuildDef(VehicleDef vehicleDef, out VehicleBui
impliedBuildDef = null;
if (vehicleDef.buildDef is null)
{
- Log.Warning($"Implied generation for vehicles is incomplete. Please define the VehicleBuildDef separately to avoid improper vehicle generation.");
+ Log.Warning($"[{vehicleDef}] Implied generation for vehicles is incomplete. Please define the VehicleBuildDef separately to avoid improper vehicle generation.");
impliedBuildDef = new VehicleBuildDef
{
defName = $"{vehicleDef.defName}_Blueprint",
diff --git a/Source/Vehicles/Harmony/PatchCategories/MapHandling.cs b/Source/Vehicles/Harmony/PatchCategories/MapHandling.cs
index 66e46171..4ae4f181 100644
--- a/Source/Vehicles/Harmony/PatchCategories/MapHandling.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/MapHandling.cs
@@ -43,9 +43,6 @@ public void PatchMethods()
VehicleHarmony.Patch(original: AccessTools.Method(typeof(MapInterface), nameof(MapInterface.MapInterfaceOnGUI_AfterMainTabs)),
postfix: new HarmonyMethod(typeof(MapHandling),
nameof(DebugOnGUIVehicleRegions)));
- VehicleHarmony.Patch(original: AccessTools.Method(typeof(Map), nameof(Map.FinalizeInit)),
- prefix: new HarmonyMethod(typeof(MapHandling),
- nameof(PreFinalizeInitRegionBuilding)));
}
///
@@ -64,9 +61,9 @@ private static IEnumerable BeachMakerTranspiler(IEnumerable().RebuildVehiclePathData();
- }
}
}
diff --git a/Source/Vehicles/Harmony/PatchCategories/Rendering.cs b/Source/Vehicles/Harmony/PatchCategories/Rendering.cs
index f75304f0..34bb0b15 100644
--- a/Source/Vehicles/Harmony/PatchCategories/Rendering.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/Rendering.cs
@@ -62,6 +62,9 @@ public void PatchMethods()
VehicleHarmony.Patch(original: TrueCenter_Thing,
prefix: new HarmonyMethod(typeof(Rendering),
nameof(TrueCenterVehicle)));
+ VehicleHarmony.Patch(original: AccessTools.Method(typeof(PawnRenderer), "ParallelGetPreRenderResults"),
+ prefix: new HarmonyMethod(typeof(Rendering),
+ nameof(DisableCachingPawnOverlays)));
VehicleHarmony.Patch(original: AccessTools.Method(typeof(Targeter), nameof(Targeter.TargeterOnGUI)),
postfix: new HarmonyMethod(typeof(Rendering),
@@ -300,6 +303,14 @@ public static bool TrueCenterVehicle(Thing t, ref Vector3 __result)
return true;
}
+ private static void DisableCachingPawnOverlays(Pawn ___pawn, ref bool disableCache)
+ {
+ if (___pawn.IsInVehicle())
+ {
+ disableCache = true;
+ }
+ }
+
/* ---------------- Hooks onto Targeter calls ---------------- */
public static void DrawTargeters()
{
diff --git a/Source/Vehicles/Harmony/PatchCategories/VehiclePathing.cs b/Source/Vehicles/Harmony/PatchCategories/VehiclePathing.cs
index 564b263c..0960b8d0 100644
--- a/Source/Vehicles/Harmony/PatchCategories/VehiclePathing.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/VehiclePathing.cs
@@ -72,6 +72,10 @@ public void PatchMethods()
nameof(SetRotationAndUpdateVehicleRegionsClipping)),
postfix: new HarmonyMethod(typeof(VehiclePathing),
nameof(SetRotationAndUpdateVehicleRegions)));
+
+ VehicleHarmony.Patch(original: AccessTools.Method(typeof(GenStep_RocksFromGrid), nameof(GenStep_RocksFromGrid.Generate)),
+ prefix: new HarmonyMethod(typeof(VehiclePathing),
+ nameof(DisableRegionUpdatingRockGen)));
}
private static void VehiclesCanTakeOrders(Pawn pawn, ref bool __result)
@@ -88,7 +92,7 @@ private static void VehiclesCanTakeOrders(Pawn pawn, ref bool __result)
///
///
///
- public static bool GotoLocationVehicles(IntVec3 clickCell, Pawn pawn, ref FloatMenuOption __result, bool suppressAutoTakeableGoto)
+ private static bool GotoLocationVehicles(IntVec3 clickCell, Pawn pawn, ref FloatMenuOption __result, bool suppressAutoTakeableGoto)
{
if (pawn is VehiclePawn vehicle)
{
@@ -187,7 +191,7 @@ public static bool GotoLocationVehicles(IntVec3 clickCell, Pawn pawn, ref FloatM
return true;
}
- public static IEnumerable GotoToilsPassthrough(IEnumerable __result, Job ___job, Pawn ___pawn)
+ private static IEnumerable GotoToilsPassthrough(IEnumerable __result, Job ___job, Pawn ___pawn)
{
bool first = true;
foreach (Toil toil in __result)
@@ -210,7 +214,7 @@ public static IEnumerable GotoToilsPassthrough(IEnumerable __result,
///
/// Bypass vanilla check for now, since it forces on-fire pawns to not be able to interrupt jobs which obviously shouldn't apply to vehicles.
///
- public static bool JobInterruptibleForVehicle(Pawn_JobTracker __instance, Pawn ___pawn, ref bool __result)
+ private static bool JobInterruptibleForVehicle(Pawn_JobTracker __instance, Pawn ___pawn, ref bool __result)
{
if (___pawn is VehiclePawn)
{
@@ -237,7 +241,7 @@ public static bool JobInterruptibleForVehicle(Pawn_JobTracker __instance, Pawn _
///
///
///
- public static void IsVehicleInNextCell(ref bool __result, Pawn ___pawn, Pawn_PathFollower __instance)
+ private static void IsVehicleInNextCell(ref bool __result, Pawn ___pawn, Pawn_PathFollower __instance)
{
if (!__result)
{
@@ -253,7 +257,7 @@ public static void IsVehicleInNextCell(ref bool __result, Pawn ___pawn, Pawn_Pat
///
///
///
- public static bool StartVehiclePath(LocalTargetInfo dest, PathEndMode peMode, Pawn ___pawn)
+ private static bool StartVehiclePath(LocalTargetInfo dest, PathEndMode peMode, Pawn ___pawn)
{
if (___pawn is VehiclePawn vehicle)
{
@@ -263,7 +267,7 @@ public static bool StartVehiclePath(LocalTargetInfo dest, PathEndMode peMode, Pa
return true;
}
- public static bool AdjacentTo8WayOrInsideVehicle(IntVec3 root, Thing t, ref bool __result)
+ private static bool AdjacentTo8WayOrInsideVehicle(IntVec3 root, Thing t, ref bool __result)
{
if (t is VehiclePawn vehicle)
{
@@ -281,7 +285,7 @@ public static bool AdjacentTo8WayOrInsideVehicle(IntVec3 root, Thing t, ref bool
///
///
///
- public static IEnumerable PathAroundVehicles(IEnumerable instructions, ILGenerator ilg)
+ private static IEnumerable PathAroundVehicles(IEnumerable instructions, ILGenerator ilg)
{
List instructionList = instructions.ToList();
for(int i = 0; i < instructionList.Count; i++)
@@ -323,7 +327,7 @@ public static IEnumerable PathAroundVehicles(IEnumerable
/// Modify CanReach result if position is claimed by Vehicle in PositionManager
///
@@ -332,7 +336,7 @@ public static IEnumerable PathAroundVehicles(IEnumerable
///
///
- public static bool CanReachVehiclePosition(IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParams, ref bool __result)
+ private static bool CanReachVehiclePosition(IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParams, ref bool __result)
{
if (peMode == PathEndMode.OnCell && !(traverseParams.pawn is VehiclePawn) && traverseParams.pawn?.Map.GetCachedMapComponent().ClaimedBy(dest.Cell) is VehiclePawn vehicle &&
vehicle.VehicleDef.passability != Traversability.Standable)
@@ -343,7 +347,7 @@ public static bool CanReachVehiclePosition(IntVec3 start, LocalTargetInfo dest,
return true;
}
- public static void ImpassableThroughVehicle(IntVec3 c, Map map, ref bool __result)
+ private static void ImpassableThroughVehicle(IntVec3 c, Map map, ref bool __result)
{
if (!__result && !PathingHelper.RegionWorking(map))
{
@@ -351,7 +355,7 @@ public static void ImpassableThroughVehicle(IntVec3 c, Map map, ref bool __resul
}
}
- public static void WalkableThroughVehicle(IntVec3 loc, ref bool __result, Map ___map)
+ private static void WalkableThroughVehicle(IntVec3 loc, ref bool __result, Map ___map)
{
if (__result && !PathingHelper.RegionWorking(___map))
{
@@ -359,7 +363,7 @@ public static void WalkableThroughVehicle(IntVec3 loc, ref bool __result, Map __
}
}
- public static void WalkableFastThroughVehicleIntVec3(IntVec3 loc, ref bool __result, Map ___map)
+ private static void WalkableFastThroughVehicleIntVec3(IntVec3 loc, ref bool __result, Map ___map)
{
if (__result && !PathingHelper.RegionWorking(___map))
{
@@ -367,7 +371,7 @@ public static void WalkableFastThroughVehicleIntVec3(IntVec3 loc, ref bool __res
}
}
- public static void WalkableFastThroughVehicleInt2(int x, int z, ref bool __result, Map ___map)
+ private static void WalkableFastThroughVehicleInt2(int x, int z, ref bool __result, Map ___map)
{
if (__result && !PathingHelper.RegionWorking(___map))
{
@@ -375,15 +379,15 @@ public static void WalkableFastThroughVehicleInt2(int x, int z, ref bool __resul
}
}
- public static void WalkableFastThroughVehicleInt(int index, ref bool __result, Map ___map)
+ private static void WalkableFastThroughVehicleInt(int index, ref bool __result, Map ___map)
{
if (__result && !PathingHelper.RegionWorking(___map))
{
__result = !PathingHelper.VehicleImpassableInCell(___map, ___map.cellIndices.IndexToCell(index));
}
}
-
- public static bool OccupiedRectVehicles(Thing t, ref CellRect __result)
+
+ private static bool OccupiedRectVehicles(Thing t, ref CellRect __result)
{
if (t is VehiclePawn vehicle)
{
@@ -393,12 +397,12 @@ public static bool OccupiedRectVehicles(Thing t, ref CellRect __result)
return true;
}
- public static void RecalculateAllPerceivedPathCostForVehicle(PathingContext ___normal)
+ private static void RecalculateAllPerceivedPathCostForVehicle(PathingContext ___normal)
{
PathingHelper.RecalculateAllPerceivedPathCosts(___normal.map);
}
- public static void RecalculatePerceivedPathCostForVehicle(IntVec3 c, PathingContext ___normal)
+ private static void RecalculatePerceivedPathCostForVehicle(IntVec3 c, PathingContext ___normal)
{
PathingHelper.RecalculatePerceivedPathCostAt(c, ___normal.map);
}
@@ -408,7 +412,7 @@ public static void RecalculatePerceivedPathCostForVehicle(IntVec3 c, PathingCont
///
///
///
- public static void SetTerrainAndUpdateVehiclePathCosts(ref IntVec3 c, Map ___map)
+ private static void SetTerrainAndUpdateVehiclePathCosts(ref IntVec3 c, Map ___map)
{
if (Current.ProgramState == ProgramState.Playing)
{
@@ -416,7 +420,7 @@ public static void SetTerrainAndUpdateVehiclePathCosts(ref IntVec3 c, Map ___map
}
}
- public static IEnumerable DeSpawnAndUpdateVehicleRegionsTranspiler(IEnumerable instructions)
+ private static IEnumerable DeSpawnAndUpdateVehicleRegionsTranspiler(IEnumerable instructions)
{
List instructionList = instructions.ToList();
@@ -439,7 +443,7 @@ public static IEnumerable DeSpawnAndUpdateVehicleRegionsTranspi
}
}
- public static IEnumerable SpawnAndUpdateVehicleRegionsTranspiler(IEnumerable instructions)
+ private static IEnumerable SpawnAndUpdateVehicleRegionsTranspiler(IEnumerable instructions)
{
List instructionList = instructions.ToList();
@@ -462,7 +466,7 @@ public static IEnumerable SpawnAndUpdateVehicleRegionsTranspile
}
}
- public static void SetPositionAndUpdateVehicleRegions(Thing __instance)
+ private static void SetPositionAndUpdateVehicleRegions(Thing __instance)
{
if (__instance.Spawned)
{
@@ -470,7 +474,7 @@ public static void SetPositionAndUpdateVehicleRegions(Thing __instance)
}
}
- public static bool SetRotationAndUpdateVehicleRegionsClipping(Thing __instance, Rot4 value)
+ private static bool SetRotationAndUpdateVehicleRegionsClipping(Thing __instance, Rot4 value)
{
if (__instance is VehiclePawn vehicle && vehicle.Spawned)
{
@@ -492,7 +496,7 @@ public static bool SetRotationAndUpdateVehicleRegionsClipping(Thing __instance,
return true;
}
- public static void SetRotationAndUpdateVehicleRegions(Thing __instance)
+ private static void SetRotationAndUpdateVehicleRegions(Thing __instance)
{
if (__instance.Spawned && (__instance.def.size.x != 1 || __instance.def.size.z != 1))
{
@@ -500,25 +504,32 @@ public static void SetRotationAndUpdateVehicleRegions(Thing __instance)
}
}
- public static void Notify_ThingAffectingVehicleRegionsSpawned(Thing b)
+ private static void DisableRegionUpdatingRockGen(Map map)
+ {
+ if (!map.TileInfo.WaterCovered)
+ {
+ PathingHelper.DisableAllRegionUpdaters(map);
+ }
+ }
+
+ private static void Notify_ThingAffectingVehicleRegionsSpawned(Thing b)
{
- //For some reason other mods love to patch the SpawnSetup method and despawn the object immediately. Extra check is necessary
+ //Some mods patch the SpawnSetup method and despawn the object immediately. Extra check is necessary
if (b.Spawned)
{
PathingHelper.ThingAffectingRegionsStateChange(b, b.Map, true);
}
}
- public static void Notify_ThingAffectingVehicleRegionsDespawned(Thing b)
+ private static void Notify_ThingAffectingVehicleRegionsDespawned(Thing b)
{
- //For some reason other mods love to patch the SpawnSetup method and despawn the object immediately. Extra check is necessary
+ //Some mods patch the SpawnSetup method and despawn the object immediately. Extra check is necessary
if (b.Spawned)
{
PathingHelper.ThingAffectingRegionsStateChange(b, b.Map, false);
}
}
-
/* ---- Helper Methods related to patches ---- */
private static void SpawnAndNotifyVehicleRegions(Thing thing, Map map)
diff --git a/Source/Vehicles/Harmony/PatchCategories/WorldHandling.cs b/Source/Vehicles/Harmony/PatchCategories/WorldHandling.cs
index 7e434661..8b909e04 100644
--- a/Source/Vehicles/Harmony/PatchCategories/WorldHandling.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/WorldHandling.cs
@@ -37,6 +37,9 @@ public void PatchMethods()
VehicleHarmony.Patch(original: AccessTools.Method(typeof(PawnBanishUtility), nameof(PawnBanishUtility.Banish)),
prefix: new HarmonyMethod(typeof(WorldHandling),
nameof(BanishPawnFromAerialVehicle)));
+ VehicleHarmony.Patch(original: AccessTools.Method(typeof(PawnUtility), nameof(PawnUtility.IsTravelingInTransportPodWorldObject)),
+ postfix: new HarmonyMethod(typeof(WorldHandling),
+ nameof(AerialVehiclesDontRandomizePrisoners)));
VehicleHarmony.Patch(original: AccessTools.Method(typeof(CameraJumper), nameof(CameraJumper.TryShowWorld)),
prefix: new HarmonyMethod(typeof(WorldHandling),
@@ -289,6 +292,14 @@ public static void DrawAerialVehicleInfo(Dialog_Trade __instance, ref Rect inRec
inRect.yMin += yUsed;
}
+ public static void AerialVehiclesDontRandomizePrisoners(Pawn pawn, ref bool __result)
+ {
+ if (ThingOwnerUtility.AnyParentIs(pawn) || ThingOwnerUtility.AnyParentIs(pawn))
+ {
+ __result = true;
+ }
+ }
+
/* -------------------- Launch Targeter -------------------- */
public static void WorldTargeterUpdate()
{
diff --git a/Source/Vehicles/Harmony/PatchCategories/WorldPathing.cs b/Source/Vehicles/Harmony/PatchCategories/WorldPathing.cs
index 3d19f36b..8ddfc399 100644
--- a/Source/Vehicles/Harmony/PatchCategories/WorldPathing.cs
+++ b/Source/Vehicles/Harmony/PatchCategories/WorldPathing.cs
@@ -46,10 +46,17 @@ public static bool AutoOrderVehicleCaravanPathing(Caravan c, int tile)
{
return false;
}
- if (!vehicleCaravan.Vehicles.All(vehicle => WorldVehiclePathGrid.Instance.Passable(tile, vehicle.VehicleDef) && vehicle.VehicleDef.vehicleType != VehicleType.Air))
+ if (vehicleCaravan.VehiclesListForReading.NullOrEmpty())
{
return false;
}
+ foreach (VehiclePawn vehicle in vehicleCaravan.VehiclesListForReading)
+ {
+ if (!WorldVehiclePathGrid.Instance.Passable(tile, vehicle.VehicleDef) || vehicle.VehicleDef.vehicleType == VehicleType.Air)
+ {
+ return false;
+ }
+ }
int bestTile = WorldHelper.BestGotoDestForVehicle(vehicleCaravan, tile);
if (bestTile >= 0)
{
diff --git a/Source/Vehicles/Harmony/UnitTesting/PerformanceTesting.cs b/Source/Vehicles/Harmony/UnitTesting/PerformanceTesting.cs
index 3341e226..33551539 100644
--- a/Source/Vehicles/Harmony/UnitTesting/PerformanceTesting.cs
+++ b/Source/Vehicles/Harmony/UnitTesting/PerformanceTesting.cs
@@ -24,9 +24,8 @@ public static class PerformanceTesting
private static double[][] averageMilliseconds;
[UnitTest(Category = "Performance", Name = "Permanent Weather (Heavy Snow)", GameState = GameState.Playing)]
- private static void SetPermanentWeather()
+ private static void UnitTest_SetPermanentWeather()
{
- Prefs.DevMode = true;
LongEventHandler.ExecuteWhenFinished(delegate ()
{
Messages.Message("Patching PermanentWeatherTick for unit testing.", MessageTypeDefOf.NeutralEvent);
@@ -39,9 +38,8 @@ private static void SetPermanentWeather()
}
[UnitTest(Category = "Performance", Name = "Component Caching", GameState = GameState.Playing)]
- private static void ProfileComponentCaching()
+ private static void UnitTest_ProfileComponentCaching()
{
- Prefs.DevMode = true;
LongEventHandler.ExecuteWhenFinished(delegate ()
{
Messages.Message("Patching ComponentCaching for unit testing.", MessageTypeDefOf.NeutralEvent);
diff --git a/Source/Vehicles/Harmony/UnitTesting/UITesting.cs b/Source/Vehicles/Harmony/UnitTesting/UITesting.cs
index cdbd2383..04fb2fb2 100644
--- a/Source/Vehicles/Harmony/UnitTesting/UITesting.cs
+++ b/Source/Vehicles/Harmony/UnitTesting/UITesting.cs
@@ -134,7 +134,7 @@ private static void UnitTest_AnimationEditor()
}
CameraJumper.TryJump(vehicle);
Find.Selector.Select(vehicle);
- vehicle.OpenInAnimator();
+ vehicle.OpenInAnimator_New();
});
VehicleDef GetVehicleDefAnimator()
diff --git a/Source/Vehicles/Harmony/VehicleHarmony.cs b/Source/Vehicles/Harmony/VehicleHarmony.cs
index f82aa019..c0869f59 100644
--- a/Source/Vehicles/Harmony/VehicleHarmony.cs
+++ b/Source/Vehicles/Harmony/VehicleHarmony.cs
@@ -31,18 +31,10 @@ internal static class VehicleHarmony
internal static ModMetaData VehicleMMD;
internal static ModContentPack VehicleMCP;
- ///
- /// Debugging
- ///
- internal static List debugLines = new List();
- internal static List> tiles = new List>(); // Pair -> TileID : Cycle
- internal static readonly bool debug = false;
- internal static readonly bool drawPaths = false;
-
private static string methodPatching = string.Empty;
internal static List updates = new List();
-
+
internal static Harmony Harmony { get; private set; } = new Harmony(VehiclesUniqueId);
internal static string VersionPath => Path.Combine(VehicleMMD.RootDir.FullName, "Version.txt");
@@ -100,7 +92,7 @@ static VehicleHarmony()
Utilities.InvokeWithLogging(RegisterTweakFieldsInEditor);
Utilities.InvokeWithLogging(PatternDef.GenerateMaterials);
- if (debug)
+ if (DebugProperties.debug)
{
//DebugHelper.Local.VehicleDef = DefDatabase.GetNamedSilentFail("VF_TestMarshal");
if (DebugHelper.Local.VehicleDef != null)
diff --git a/Source/Vehicles/Misc/DefModExtension/RoofDefPositionStateDefModExtension.cs b/Source/Vehicles/Misc/DefModExtension/RoofDefPositionStateDefModExtension.cs
new file mode 100644
index 00000000..bbe2baf5
--- /dev/null
+++ b/Source/Vehicles/Misc/DefModExtension/RoofDefPositionStateDefModExtension.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace Vehicles
+{
+ public class RoofDefPositionStateDefModExtension : DefModExtension
+ {
+ public LandingTargeter.PositionState state = LandingTargeter.PositionState.Invalid;
+ }
+}
diff --git a/Source/Vehicles/Misc/DefOf/VehicleEventDefOf.cs b/Source/Vehicles/Misc/DefOf/VehicleEventDefOf.cs
index 56656956..11b70d58 100644
--- a/Source/Vehicles/Misc/DefOf/VehicleEventDefOf.cs
+++ b/Source/Vehicles/Misc/DefOf/VehicleEventDefOf.cs
@@ -35,6 +35,8 @@ static VehicleEventDefOf()
//Comps
public static VehicleEventDef OutOfFuel;
public static VehicleEventDef Refueled;
+ public static VehicleEventDef Deployed;
+ public static VehicleEventDef Undeployed;
//Stats
public static VehicleEventDef DamageTaken;
@@ -51,5 +53,11 @@ static VehicleEventDefOf()
public static VehicleEventDef AerialVehicleCrashLanding;
public static VehicleEventDef AerialVehicleLeftMap;
public static VehicleEventDef AerialVehicleOrdered;
+
+ //Upgrades
+ public static VehicleEventDef VehicleUpgradeEnqueued;
+ public static VehicleEventDef VehicleUpgradeCompleted;
+ public static VehicleEventDef VehicleUpgradeRefundEnqueued;
+ public static VehicleEventDef VehicleUpgradeRefundCompleted;
}
}
diff --git a/Source/Vehicles/Misc/DefOf/VehicleStatUpgradeCategoryDefOf.cs b/Source/Vehicles/Misc/DefOf/VehicleStatUpgradeCategoryDefOf.cs
index 8a974828..4db3beea 100644
--- a/Source/Vehicles/Misc/DefOf/VehicleStatUpgradeCategoryDefOf.cs
+++ b/Source/Vehicles/Misc/DefOf/VehicleStatUpgradeCategoryDefOf.cs
@@ -10,12 +10,18 @@ namespace Vehicles
[DefOf]
public class VehicleStatUpgradeCategoryDefOf
{
+ //Fuel
public static StatUpgradeCategoryDef FuelCapacity;
- public static StatUpgradeCategoryDef FuelEfficiency;
public static StatUpgradeCategoryDef FuelConsumptionRate;
+ public static StatUpgradeCategoryDef ChargeRate;
+ public static StatUpgradeCategoryDef DischargeRate;
+
+ //World Map
public static StatUpgradeCategoryDef WorldSpeedMultiplier;
- public static StatUpgradeCategoryDef OffRoadEfficiency;
- public static StatUpgradeCategoryDef WinterPathCost;
+ public static StatUpgradeCategoryDef OffRoadMultiplier;
+ public static StatUpgradeCategoryDef WinterCostMultiplier;
+
+ //Combat
public static StatUpgradeCategoryDef PawnCollisionMultiplier;
public static StatUpgradeCategoryDef PawnCollisionRecoilMultiplier;
diff --git a/Source/Vehicles/Misc/Enums/UI/WorldPathingDebugType.cs b/Source/Vehicles/Misc/Enums/UI/WorldPathingDebugType.cs
index a0ba5f79..6d6a8f7c 100644
--- a/Source/Vehicles/Misc/Enums/UI/WorldPathingDebugType.cs
+++ b/Source/Vehicles/Misc/Enums/UI/WorldPathingDebugType.cs
@@ -12,5 +12,6 @@ public enum WorldPathingDebugType
None,
PathCosts,
Reachability,
+ WinterPct,
}
}
diff --git a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Debug.cs b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Debug.cs
index ae150c8d..94ae9833 100644
--- a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Debug.cs
+++ b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Debug.cs
@@ -17,7 +17,7 @@ public class Section_Debug : SettingsSection
{
public const float ButtonHeight = 30f;
public const float VerticalGap = 2f;
- public const int ButtonRows = 3;
+ public const int ButtonRows = 4;
public const int DebugSectionColumns = 2;
public bool debugDraftAnyVehicle;
@@ -90,7 +90,11 @@ public override void ExposeData()
Scribe_Values.Look(ref debugDrawVehiclePathCosts, nameof(debugDrawVehiclePathCosts));
Scribe_Values.Look(ref debugDrawPathfinderSearch, nameof(debugDrawPathfinderSearch));
- Scribe_Values.Look(ref debugSpawnVehicleBuildingGodMode, nameof(debugSpawnVehicleBuildingGodMode));
+ if (DebugProperties.debug)
+ {
+ Scribe_Values.Look(ref debugSpawnVehicleBuildingGodMode, nameof(debugSpawnVehicleBuildingGodMode));
+ }
+
Scribe_Values.Look(ref debugUseMultithreading, nameof(debugUseMultithreading), defaultValue: true);
Scribe_Values.Look(ref debugLoadAssetBundles, nameof(debugLoadAssetBundles), defaultValue: true);
@@ -100,6 +104,7 @@ public override void ExposeData()
public override void DrawSection(Rect rect)
{
Rect devModeRect = rect.ContractedBy(10);
+ devModeRect.yMin += VehicleMod.ResetImageSize + 5;
float buttonRowHeight = (ButtonHeight * ButtonRows + VerticalGap * (ButtonRows - 1));
devModeRect.height = devModeRect.height - buttonRowHeight;
@@ -109,14 +114,28 @@ public override void DrawSection(Rect rect)
{
GUIState.Push();
{
+#if DEBUG
listingStandard.Header("VF_DevMode_Logging".Translate(), ListingExtension.BannerColor, fontSize: GameFont.Small, anchor: TextAnchor.MiddleCenter);
listingStandard.CheckboxLabeled("VF_DevMode_DebugLogging".Translate(), ref debugLogging, "VF_DevMode_DebugLoggingTooltip".Translate());
listingStandard.CheckboxLabeled("VF_DevMode_DebugPathCostRecalculationLogging".Translate(), ref debugPathCostChanges, "VF_DevMode_DebugPathCostRecalculationLoggingTooltip".Translate());
+#endif
listingStandard.Header("VF_DevMode_Troubleshooting".Translate(), ListingExtension.BannerColor, fontSize: GameFont.Small, anchor: TextAnchor.MiddleCenter);
listingStandard.CheckboxLabeled("VF_DevMode_DebugDraftAnyVehicle".Translate(), ref debugDraftAnyVehicle, "VF_DevMode_DebugDraftAnyVehicleTooltip".Translate());
+ bool shootAnyTurret = debugShootAnyTurret;
listingStandard.CheckboxLabeled("VF_DevMode_DebugShootAnyTurret".Translate(), ref debugShootAnyTurret, "VF_DevMode_DebugShootAnyTurretTooltip".Translate());
-
+
+ if (shootAnyTurret != debugShootAnyTurret && Current.ProgramState == ProgramState.Playing && !Find.Maps.NullOrEmpty())
+ {
+ foreach (Map map in Find.Maps)
+ {
+ foreach (VehiclePawn vehicle in map.AllPawnsOnMap(Faction.OfPlayer))
+ {
+ vehicle.CompVehicleTurrets?.RecacheTurretPermissions();
+ }
+ }
+ }
+#if DEBUG
listingStandard.Header("Debugging Only", ListingExtension.BannerColor, fontSize: GameFont.Small, anchor: TextAnchor.MiddleCenter);
listingStandard.CheckboxLabeledWithMessage("Raiders / Traders (Experimental)", delegate (bool value)
@@ -125,6 +144,7 @@ public override void DrawSection(Rect rect)
}, ref debugAllowRaiders, "Enables vehicle generation for NPCs.\n NOTE: This is an experimental feature. Use at your own risk.");
listingStandard.CheckboxLabeled("VF_DevMode_DebugSpawnVehiclesGodMode".Translate(), ref debugSpawnVehicleBuildingGodMode, "VF_DevMode_DebugSpawnVehiclesGodModeTooltip".Translate());
+
bool checkOn = debugUseMultithreading;
listingStandard.CheckboxLabeled("Use Multithreading", ref checkOn);
@@ -145,49 +165,40 @@ public override void DrawSection(Rect rect)
}
}
listingStandard.CheckboxLabeled("Load AssetBundles", ref debugLoadAssetBundles);
-
- if (Current.ProgramState == ProgramState.Playing && !Find.Maps.NullOrEmpty())
- {
- foreach (Map map in Find.Maps)
- {
- foreach (VehiclePawn vehicle in map.AllPawnsOnMap(Faction.OfPlayer))
- {
- if (vehicle.CompVehicleTurrets != null)
- {
- vehicle.CompVehicleTurrets.RecacheTurretPermissions();
- }
- }
- }
- }
+#endif
listingStandard.Header("VF_DevMode_Drawers".Translate(), ListingExtension.BannerColor, fontSize: GameFont.Small, anchor: TextAnchor.MiddleCenter);
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawUpgradeNodeGrid".Translate(), ref debugDrawNodeGrid, "VF_DevMode_DebugDrawUpgradeNodeGridTooltip".Translate());
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawHitbox".Translate(), ref debugDrawHitbox, "VF_DevMode_DebugDrawHitboxTooltip".Translate());
- GUIState.Disable();
+#if DEBUG
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawVehicleTracks".Translate(), ref debugDrawVehicleTracks, "VF_DevMode_DebugDrawVehicleTracksTooltip".Translate());
- GUIState.Enable();
+#endif
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawBumpers".Translate(), ref debugDrawBumpers, "VF_DevMode_DebugDrawBumpersTooltip".Translate());
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawLordMeetingPoint".Translate(), ref debugDrawLordMeetingPoint, "VF_DevMode_DebugDrawLordMeetingPointTooltip".Translate());
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawFleePoints".Translate(), ref debugDrawFleePoint, "VF_DevMode_DebugDrawFleePointsTooltip".Translate());
- listingStandard.NewColumn();
listingStandard.Header("VF_DevMode_Pathing".Translate(), ListingExtension.BannerColor, fontSize: GameFont.Small, anchor: TextAnchor.MiddleCenter);
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawVehiclePathingCosts".Translate(), ref debugDrawVehiclePathCosts, "VF_DevMode_DebugDrawVehiclePathingCostsTooltip".Translate());
listingStandard.CheckboxLabeled("VF_DevMode_DebugDrawPathfinderSearch".Translate(), ref debugDrawPathfinderSearch, "VF_DevMode_DebugDrawPathfinderSearchTooltip".Translate());
-
- DoColumnButtons();
}
GUIState.Pop();
}
listingStandard.End();
- Rect devModeButtonsRect = new Rect(devModeRect);
- devModeButtonsRect.y = devModeRect.yMax;
+ DoBottomButtons(devModeRect, buttonRowHeight);
+
+ listingStandard.End();
+ }
+
+ private void DoBottomButtons(Rect rect, float buttonRowHeight)
+ {
+ Rect devModeButtonsRect = new Rect(rect);
+ devModeButtonsRect.y = rect.yMax;
devModeButtonsRect.height = buttonRowHeight;
- listingStandard.ColumnWidth = devModeRect.width / 3;
+ listingStandard.ColumnWidth = devModeButtonsRect.width / 3 - 17;
listingStandard.Begin(devModeButtonsRect);
{
if (listingStandard.ButtonText("VF_DevMode_ShowRecentNews".Translate()))
@@ -195,117 +206,117 @@ public override void DrawSection(Rect rect)
SoundDefOf.Click.PlayOneShotOnCamera();
ShowAllUpdates();
}
+#if DEBUG
if (listingStandard.ButtonText("VF_DevMode_OpenQuickTestSettings".Translate()))
{
SoundDefOf.Click.PlayOneShotOnCamera();
UnitTesting.OpenMenu();
}
+#endif
+
+ if (listingStandard.ButtonText("VF_DevMode_LogThreadActivity".Translate(), "VF_DevMode_LogThreadActivityTooltip"))
+ {
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ Find.WindowStack.Add(new Dialog_DedicatedThreadActivity(delegate ()
+ {
+ if (Find.CurrentMap == null)
+ {
+ return null;
+ }
+
+ VehicleMapping vehicleMapping = Find.CurrentMap.GetCachedMapComponent();
+ return vehicleMapping.dedicatedThread;
+ }));
+ }
+
if (listingStandard.ButtonText("VF_DevMode_GraphEditor".Translate()))
{
SoundDefOf.Click.PlayOneShotOnCamera();
Find.WindowStack.Add(new Dialog_GraphEditor());
}
- }
- listingStandard.End();
- }
- private void DoColumnButtons()
- {
- listingStandard.Gap(2);
- Rect buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "VF_DevMode_DebugPathfinderDebugging".Translate()))
- {
- SoundDefOf.Click.PlayOneShotOnCamera();
- RegionDebugMenu();
- }
- TooltipHandler.TipRegionByKey(buttonRect, "VF_DevMode_DebugPathfinderDebuggingTooltip");
+ if (listingStandard.ButtonText("VF_DevMode_DebugPathfinderDebugging".Translate(), "VF_DevMode_DebugPathfinderDebuggingTooltip"))
+ {
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ RegionDebugMenu();
+ }
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "VF_DevMode_DebugWorldPathfinderDebugging".Translate()))
- {
- SoundDefOf.Click.PlayOneShotOnCamera();
- WorldPathingDebugMenu();
- }
- TooltipHandler.TipRegionByKey(buttonRect, "VF_DevMode_DebugWorldPathfinderDebuggingTooltip");
+ if (listingStandard.ButtonText("VF_DevMode_DebugWorldPathfinderDebugging".Translate(), "VF_DevMode_DebugWorldPathfinderDebuggingTooltip"))
+ {
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ WorldPathingDebugMenu();
+ }
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "Output Material Cache"))
- {
- SoundDefOf.Click.PlayOneShotOnCamera();
- RGBMaterialPool.LogAllMaterials();
- }
+#if DEBUG
+ if (listingStandard.ButtonText("Output Material Cache"))
+ {
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ RGBMaterialPool.LogAllMaterials();
+ }
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "Output Owners"))
- {
- Map map = Find.CurrentMap;
- if (map != null)
+ if (listingStandard.ButtonText("Output Owners"))
{
- Log.Message($"Vehicles = {DefDatabase.AllDefsListForReading.Count}");
- foreach (VehicleDef vehicleDef in DefDatabase.AllDefsListForReading)
+ Map map = Find.CurrentMap;
+ if (map != null)
{
- Log.Message($"{vehicleDef} DefIndex = {vehicleDef.DefIndex}");
- }
- Log.Message("-------");
- VehicleMapping mapping = map.GetCachedMapComponent();
- Log.Message($"Total Owners = {mapping.Owners.Count}");
- foreach (VehicleDef vehicleDef in mapping.Owners)
- {
- List piggies = mapping.GetPiggies(vehicleDef);
- Log.Message($"Owner: {vehicleDef} Piggies=({string.Join(",", piggies.Select(def => def.defName))})");
+ Log.Message($"Vehicles = {DefDatabase.AllDefsListForReading.Count}");
+ foreach (VehicleDef vehicleDef in DefDatabase.AllDefsListForReading)
+ {
+ Log.Message($"{vehicleDef} DefIndex = {vehicleDef.DefIndex}");
+ }
+ Log.Message("-------");
+ VehicleMapping mapping = map.GetCachedMapComponent();
+ Log.Message($"Total Owners = {mapping.Owners.Count}");
+ foreach (VehicleDef vehicleDef in mapping.Owners)
+ {
+ List piggies = mapping.GetPiggies(vehicleDef);
+ Log.Message($"Owner: {vehicleDef} Piggies=({string.Join(",", piggies.Select(def => def.defName))})");
+ }
}
}
- }
+#endif
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "Regenerate All Regions"))
- {
- LongEventHandler.QueueLongEvent(delegate ()
+ if (listingStandard.ButtonText("Regenerate All Regions"))
{
- SoundDefOf.Click.PlayOneShotOnCamera();
- foreach (Map map in Find.Maps)
+ LongEventHandler.QueueLongEvent(delegate ()
{
- VehicleMapping mapping = MapComponentCache.GetComponent(map);
- foreach (VehicleDef vehicleDef in VehicleHarmony.AllMoveableVehicleDefs)
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ foreach (Map map in Find.Maps)
{
- mapping[vehicleDef].VehiclePathGrid.RecalculateAllPerceivedPathCosts();
- if (mapping.IsOwner(vehicleDef))
+ VehicleMapping mapping = MapComponentCache.GetComponent(map);
+ foreach (VehicleDef vehicleDef in VehicleHarmony.AllMoveableVehicleDefs)
{
- mapping[vehicleDef].VehicleRegionDirtyer.SetAllDirty();
- mapping[vehicleDef].VehicleRegionAndRoomUpdater.TryRebuildVehicleRegions();
+ mapping[vehicleDef].VehiclePathGrid.RecalculateAllPerceivedPathCosts();
+ if (mapping.IsOwner(vehicleDef))
+ {
+ mapping[vehicleDef].VehicleRegionDirtyer.SetAllDirty();
+ mapping[vehicleDef].VehicleRegionAndRoomUpdater.TryRebuildVehicleRegions();
+ }
}
}
- }
- }, "Regenerating Regions", false, null);
- }
+ }, "Regenerating Regions", false, null);
+ }
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "Clear Region Cache"))
- {
- LongEventHandler.QueueLongEvent(delegate ()
+ if (listingStandard.ButtonText("Clear Region Cache"))
{
- SoundDefOf.Click.PlayOneShotOnCamera();
- foreach (Map map in Find.Maps)
+ LongEventHandler.QueueLongEvent(delegate ()
{
- VehicleMapping mapping = map.GetCachedMapComponent();
- foreach (VehicleDef vehicleDef in VehicleHarmony.AllMoveableVehicleDefs)
+ SoundDefOf.Click.PlayOneShotOnCamera();
+ foreach (Map map in Find.Maps)
{
- mapping[vehicleDef].VehicleReachability.ClearCache();
+ VehicleMapping mapping = map.GetCachedMapComponent();
+ foreach (VehicleDef vehicleDef in VehicleHarmony.AllMoveableVehicleDefs)
+ {
+ mapping[vehicleDef].VehicleReachability.ClearCache();
+ }
}
- }
- }, "Clearing Region Cache", false, null);
- }
+ }, "Clearing Region Cache", false, null);
+ }
- listingStandard.Gap(2);
- buttonRect = listingStandard.GetRect(30);
- if (Widgets.ButtonText(buttonRect, "Flash Path Costs"))
- {
- OpenFlashPathCostsMenu();
+ if (listingStandard.ButtonText("Flash Path Costs"))
+ {
+ OpenFlashPathCostsMenu();
+ }
}
}
diff --git a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Main.cs b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Main.cs
index 06a4ce8f..30ed6c23 100644
--- a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Main.cs
+++ b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Main.cs
@@ -233,6 +233,8 @@ public override void DrawSection(Rect rect)
listingStandard.CheckboxLabeled("VF_OpportunisticTicking".Translate(), ref opportunisticTicking, "VF_OpportunisticTickingTooltip".Translate());
listingStandard.NewColumn();
+
+#if !FISHING_DISABLED
string fishingHeader = "VF_Fishing".Translate();
if (!FishingCompatibility.Active)
{
@@ -253,6 +255,7 @@ public override void DrawSection(Rect rect)
listingStandard.Gap(8);
GUIState.Enable();
+#endif
listingStandard.Header("VF_AerialVehicles".Translate(), ListingExtension.BannerColor, GameFont.Small, TextAnchor.MiddleCenter);
//listingStandard.Gap(4);
diff --git a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Vehicles.cs b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Vehicles.cs
index 05410bc5..3ae58c41 100644
--- a/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Vehicles.cs
+++ b/Source/Vehicles/Misc/ModSettings/SettingsSection/Section_Vehicles.cs
@@ -157,11 +157,7 @@ private void DrawVehicleOptions(Rect menuRect)
Widgets.BeginGroup(iconRect);
{
Rect vehicleTexRect = new Rect(Vector2.zero, iconRect.size);
- drawStatusMessage = VehicleGraphics.DrawVehicleDef(vehicleTexRect, VehicleMod.selectedDef, rot: directionFacing.TryGetValue(VehicleMod.selectedDef, currentVehicleFacing), withoutTurrets: true);
- if (!drawStatusMessage.NullOrEmpty())
- {
- throw new Exception(drawStatusMessage);
- }
+ VehicleGraphics.DrawVehicleDef(vehicleTexRect, VehicleMod.selectedDef, rot: directionFacing.TryGetValue(VehicleMod.selectedDef, currentVehicleFacing), withoutTurrets: true);
}
Widgets.EndGroup();
diff --git a/Source/Vehicles/Pathing/Map/VehiclePathFinder.cs b/Source/Vehicles/Pathing/Map/VehiclePathFinder.cs
index c23bd9ac..1126ac48 100644
--- a/Source/Vehicles/Pathing/Map/VehiclePathFinder.cs
+++ b/Source/Vehicles/Pathing/Map/VehiclePathFinder.cs
@@ -125,6 +125,11 @@ public VehiclePathFinder(VehicleMapping mapping, VehicleDef vehicleDef)
postCalculatedCells = new Dictionary();
}
+ public void PostInit()
+ {
+ vehiclePathGrid = mapping[vehicleDef].VehiclePathGrid;
+ }
+
///
/// Find path from to
///
@@ -188,7 +193,6 @@ public PawnPath FindVehiclePath(IntVec3 start, LocalTargetInfo dest, TraversePar
}
cellIndices = mapping.map.cellIndices;
- vehiclePathGrid = mapping[vehicleDef].VehiclePathGrid;
this.edificeGrid = mapping.map.edificeGrid.InnerArray;
blueprintGrid = mapping.map.blueprintGrid.InnerArray;
int x = dest.Cell.x;
@@ -200,7 +204,7 @@ public PawnPath FindVehiclePath(IntVec3 start, LocalTargetInfo dest, TraversePar
bool freeTraversal = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater;
CellRect cellRect = CalculateDestinationRect(dest, peMode);
bool singleRect = cellRect.Width == 1 && cellRect.Height == 1;
- int[] vehicleArray = vehiclePathGrid.pathGrid;
+ int[] pathGrid = vehiclePathGrid.pathGrid;
TerrainDef[] topGrid = mapping.map.terrainGrid.topGrid;
EdificeGrid edificeGrid = mapping.map.edificeGrid;
int searchCount = 0;
@@ -343,11 +347,11 @@ public PawnPath FindVehiclePath(IntVec3 start, LocalTargetInfo dest, TraversePar
int cellToCheckIndex = cellIndices.CellToIndex(cellInRect);
if (cellInRect == cellToCheck)
{
- rootCost = vehicleArray[cellToCheckIndex] * RootPosWeight;
+ rootCost = pathGrid[cellToCheckIndex] * RootPosWeight;
}
else
{
- totalAreaCost += vehicleArray[cellToCheckIndex] * (1 - RootPosWeight);
+ totalAreaCost += pathGrid[cellToCheckIndex] * (1 - RootPosWeight);
}
}
tickCost += Mathf.RoundToInt(totalAreaCost / (minSize * 2 - 1)); //minSize^2 - 1 to account for average of all cells except root
diff --git a/Source/Vehicles/Pathing/Map/VehicleRegionUpdateCatalog.cs b/Source/Vehicles/Pathing/Map/VehicleRegionUpdateCatalog.cs
deleted file mode 100644
index bcf6a620..00000000
--- a/Source/Vehicles/Pathing/Map/VehicleRegionUpdateCatalog.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Verse;
-using UnityEngine;
-using SmashTools;
-
-namespace Vehicles
-{
- ///
- /// Tracks which region sets need to be updated
- ///
- public class VehicleRegionUpdateCatalog //: DetachedMapComponent
- {
- private int[] vehicleCounts;
- private HashSet updateWanters = new HashSet();
-
- public VehicleRegionUpdateCatalog(Map map) //: base(map)
- {
- vehicleCounts = new int[DefDatabase.AllDefsListForReading.Count];
- }
-
- public void Notify_VehicleSpawned(VehiclePawn vehicle)
- {
- vehicleCounts[vehicle.VehicleDef.DefIndex]++;
- if (vehicleCounts[vehicle.VehicleDef.DefIndex] > 0)
- {
- updateWanters.Add(vehicle.VehicleDef);
- }
- }
-
- public void Notify_VehicleDespawned(VehiclePawn vehicle)
- {
- vehicleCounts[vehicle.VehicleDef.DefIndex]--;
- if (vehicleCounts[vehicle.VehicleDef.DefIndex] == 0)
- {
- updateWanters.Remove(vehicle.VehicleDef);
- }
- }
- }
-}
diff --git a/Source/Vehicles/Pathing/Map/Vehicle_PathFollower.cs b/Source/Vehicles/Pathing/Map/Vehicle_PathFollower.cs
index e511c957..25e3d401 100644
--- a/Source/Vehicles/Pathing/Map/Vehicle_PathFollower.cs
+++ b/Source/Vehicles/Pathing/Map/Vehicle_PathFollower.cs
@@ -646,10 +646,6 @@ private void TrySetNewPath_Threaded()
}
else
{
- if (!VehicleMod.settings.debug.debugUseMultithreading)
- {
- Log.WarningOnce($"Finding path on main thread. DedicatedThread was not available.", vehicle.Map.GetHashCode());
- }
TrySetNewPath();
CalculatingPath = false;
}
diff --git a/Source/Vehicles/Pathing/RegionGrid/GenGridVehicles.cs b/Source/Vehicles/Pathing/RegionGrid/GenGridVehicles.cs
index 3bebe5e3..6df830dc 100644
--- a/Source/Vehicles/Pathing/RegionGrid/GenGridVehicles.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/GenGridVehicles.cs
@@ -21,7 +21,16 @@ public static class GenGridVehicles
///
public static bool Walkable(this IntVec3 cell, VehicleDef vehicleDef, Map map)
{
- return map.GetCachedMapComponent()[vehicleDef].VehiclePathGrid.Walkable(cell);
+ if (map == null)
+ {
+ return false;
+ }
+ return MapComponentCache.GetComponent(map)[vehicleDef].VehiclePathGrid.Walkable(cell);
+ }
+
+ public static bool Walkable(this IntVec3 cell, VehicleDef vehicleDef, VehicleMapping mapping)
+ {
+ return mapping[vehicleDef].VehiclePathGrid.Walkable(cell);
}
///
@@ -48,7 +57,7 @@ public static bool StandableUnknown(this IntVec3 cell, Pawn pawn, Map map)
///
public static bool Standable(this IntVec3 cell, VehiclePawn vehicle, Map map)
{
- if (!map.GetCachedMapComponent()[vehicle.VehicleDef].VehiclePathGrid.Walkable(cell))
+ if (!MapComponentCache.GetComponent(map)[vehicle.VehicleDef].VehiclePathGrid.Walkable(cell))
{
return false;
}
@@ -71,7 +80,7 @@ public static bool Standable(this IntVec3 cell, VehiclePawn vehicle, Map map)
///
public static bool Standable(this IntVec3 cell, VehicleDef vehicleDef, Map map)
{
- if (!map.GetCachedMapComponent()[vehicleDef].VehiclePathGrid.Walkable(cell))
+ if (!MapComponentCache.GetComponent(map)[vehicleDef].VehiclePathGrid.Walkable(cell))
{
return false;
}
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleMapping.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleMapping.cs
index 68e61c6e..baf3f1f2 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleMapping.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleMapping.cs
@@ -1,16 +1,21 @@
-using System.Collections.Generic;
+using System;
+using System.Reflection;
+using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Linq;
using Verse;
using UnityEngine;
+using HarmonyLib;
using SmashTools;
using SmashTools.Performance;
+using System.Text;
namespace Vehicles
{
///
/// MapComponent container for all pathing related sub-components for vehicles
///
+ [StaticConstructorOnStartup]
public sealed class VehicleMapping : MapComponent
{
private const int EventMapId = 0;
@@ -20,15 +25,15 @@ public sealed class VehicleMapping : MapComponent
private int[] piggyToOwner;
private List owners = new List();
- private int buildingFor = -1;
+ private VehicleDef buildingFor;
private int vehicleRegionGridIndexChecking = 0;
internal DedicatedThread dedicatedThread;
+ private bool initialized;
+
public VehicleMapping(Map map) : base(map)
{
- ConstructComponents();
- dedicatedThread = GetDedicatedThread(map);
}
///
@@ -39,27 +44,36 @@ public VehicleMapping(Map map) : base(map)
public DedicatedThread Thread => dedicatedThread;
///
- /// Check to make sure dedicated thread is instantiated and running.
+ /// Check if is initialized and running.
///
- /// Verify this is true before queueing up a method, otherwise you may just be sending it to the void where it will never be executed ever.
- public bool ThreadAvailable => dedicatedThread != null && dedicatedThread.thread.IsAlive;
+ public bool ThreadAlive
+ {
+ get
+ {
+ return dedicatedThread != null && dedicatedThread.thread.IsAlive;
+ }
+ }
///
- /// If dedicated thread is given long task, it should be marked as having a long operation so smaller tasks can avoid queueing up with a long wait time
+ /// Check if is alive and not in long operation.
///
- public bool ThreadBusy => !dedicatedThread.InLongOperation;
+ /// Verify this is true before queueing up a method, otherwise you may just be sending it to the void where it will never be executed ever.
+ public bool ThreadAvailable
+ {
+ get
+ {
+ return ThreadAlive && !ThreadBusy;
+ }
+ }
///
- /// Retrieve all for this map
+ /// DedicatedThread is either processing a long operation in its queue or the queue has grown large enough to warrant waiting.
///
- public IEnumerable AllPathData
+ public bool ThreadBusy
{
get
{
- foreach (VehiclePathData pathData in vehicleData)
- {
- yield return pathData;
- }
+ return dedicatedThread.InLongOperation || dedicatedThread.QueueCount > 10000;
}
}
@@ -72,12 +86,16 @@ public VehiclePathData this[VehicleDef vehicleDef]
get
{
#if DEBUG
- if (buildingFor == vehicleDef.DefIndex)
+ if (buildingFor == vehicleDef)
{
- Log.Error($"Trying to pull VehiclePathData by indexing when it's currently in the middle of generation. Recursion is not supported here!");
- return VehiclePathData.Invalid;
+ Log.Error($"Trying to pull VehiclePathData by indexing when it's currently in the middle of generation. Recursion is not supported here.");
+ return null;
}
#endif
+ if (!initialized)
+ {
+ ConstructComponents();
+ }
VehiclePathData pathData = vehicleData[vehicleDef.DefIndex];
if (!pathData.IsValid)
{
@@ -86,7 +104,7 @@ public VehiclePathData this[VehicleDef vehicleDef]
if (!UnityData.IsInMainThread)
{
Log.Error($"Unable to generate path data outside of the main thread. May encounter thread safety issues.");
- return VehiclePathData.Invalid;
+ return null;
}
return GeneratePathData(vehicleDef);
@@ -168,21 +186,54 @@ public List GetPiggies(VehicleDef ownerDef)
///
/// Finalize initialization for map component
///
- public void RebuildVehiclePathData()
+ public override void FinalizeInit()
{
- foreach (VehiclePathData vehiclePathData in AllPathData)
+ base.FinalizeInit();
+
+ if (!initialized)
+ {
+ ConstructComponents();
+ }
+
+ Ext_Map.StashLongEventText();
+
+ StringBuilder eventTextBuilder = new StringBuilder();
+
+ DeepProfiler.Start("Vehicle PathGrids".Translate());
+ foreach (VehiclePathData vehiclePathData in vehicleData)
{
//Needs to check validity, non-pathing vehicles are still indexed since sequential vehicles will have higher index numbers
if (vehiclePathData.IsValid)
{
+ eventTextBuilder.Clear();
+ eventTextBuilder.AppendLine("VF_GeneratingPathGrids".Translate());
+ eventTextBuilder.AppendLine(vehiclePathData.Owner.defName);
+ LongEventHandler.SetCurrentEventText(eventTextBuilder.ToString());
+
vehiclePathData.VehiclePathGrid.RecalculateAllPerceivedPathCosts();
- if (IsOwner(vehiclePathData.Owner) && vehiclePathData.UsesRegions)
- {
- vehiclePathData.VehicleRegionAndRoomUpdater.Enabled = true;
- vehiclePathData.VehicleRegionAndRoomUpdater.RebuildAllVehicleRegions();
- }
}
}
+ DeepProfiler.End();
+
+ DeepProfiler.Start("Vehicle Regions");
+ foreach (VehicleDef vehicleDef in owners)
+ {
+ eventTextBuilder.Clear();
+ eventTextBuilder.AppendLine("VF_GeneratingRegions".Translate());
+ eventTextBuilder.AppendLine(vehicleDef.defName);
+ LongEventHandler.SetCurrentEventText(eventTextBuilder.ToString());
+
+ VehiclePathData vehiclePathData = this[vehicleDef];
+ vehiclePathData.VehicleRegionAndRoomUpdater.Enabled = true;
+ vehiclePathData.VehicleRegionAndRoomUpdater.RebuildAllVehicleRegions();
+ }
+ DeepProfiler.End();
+
+ DeepProfiler.Start("Fetching DedicatedThread");
+ dedicatedThread = GetDedicatedThread(map); //Init dedicated thread after map generation to avoid duplicate pathgrid and region recalcs
+ DeepProfiler.End();
+
+ Ext_Map.RevertLongEventText();
}
///
@@ -195,10 +246,12 @@ public void ConstructComponents()
piggyToOwner = new int[size].Populate(-1);
owners.Clear();
- foreach (VehicleDef vehicleDef in DefDatabase.AllDefsListForReading) //Even shuttles need path data for landing
- {
- GeneratePathData(vehicleDef);
- }
+
+ initialized = true;
+
+ GenerateAllPathData();
+
+ PathingHelper.DisableAllRegionUpdaters(map);
}
public override void ExposeData()
@@ -215,7 +268,7 @@ public override void ExposeData()
public override void MapRemoved()
{
- bool result = ReleaseThread();
+ ReleaseThread();
}
internal bool ReleaseThread()
@@ -246,6 +299,20 @@ public override void MapComponentUpdate()
}
}
+ private void GenerateAllPathData()
+ {
+ Ext_Map.StashLongEventText();
+ LongEventHandler.SetCurrentEventText("VF_GeneratingPathData".Translate());
+ DeepProfiler.Start("Generating VehiclePathData");
+ foreach (VehicleDef vehicleDef in DefDatabase.AllDefsListForReading) //Even shuttles need path data for landing
+ {
+ GeneratePathData(vehicleDef);
+ }
+ DeepProfiler.End();
+
+ Ext_Map.RevertLongEventText();
+ }
+
///
/// Generate new for
///
@@ -253,8 +320,10 @@ public override void MapComponentUpdate()
private VehiclePathData GeneratePathData(VehicleDef vehicleDef, bool compress = true)
{
VehiclePathData vehiclePathData = new VehiclePathData(vehicleDef);
+ vehicleData[vehicleDef.DefIndex] = vehiclePathData;
+ bool newOwner = false;
- buildingFor = vehicleDef.DefIndex;
+ buildingFor = vehicleDef;
{
vehiclePathData.VehiclePathGrid = new VehiclePathGrid(this, vehicleDef);
vehiclePathData.VehiclePathFinder = new VehiclePathFinder(this, vehicleDef);
@@ -267,12 +336,20 @@ private VehiclePathData GeneratePathData(VehicleDef vehicleDef, bool compress =
}
else
{
- vehiclePathData.ReachabilityData = new VehicleReachabilitySettings(this, vehicleDef);
+ vehiclePathData.ReachabilityData = new VehicleReachabilitySettings(this, vehicleDef, vehiclePathData);
AddOwner(vehicleDef);
+ newOwner = true;
}
- vehicleData[vehicleDef.DefIndex] = vehiclePathData;
}
- buildingFor = -1;
+ buildingFor = null;
+
+ vehiclePathData.VehiclePathGrid.PostInit();
+ vehiclePathData.VehiclePathFinder.PostInit();
+ if (newOwner)
+ {
+ vehiclePathData.ReachabilityData.PostInit();
+ }
+
return vehiclePathData;
}
@@ -297,13 +374,11 @@ private bool TryGetOwner(VehiclePathData vehiclePathData, out int ownerId)
}
///
- /// Container for all path related sub-components specific to a .
+ /// Container for all path related subcomponents specific to a .
///
/// Stores data strictly for deviations from vanilla regarding impassable values
- public struct VehiclePathData
+ public class VehiclePathData
{
- private readonly VehicleDef vehicleDef;
-
private readonly HashSet impassableThingDefs;
private readonly HashSet impassableTerrain;
private readonly int size;
@@ -311,7 +386,7 @@ public struct VehiclePathData
public VehiclePathData(VehicleDef vehicleDef)
{
- this.vehicleDef = vehicleDef;
+ Owner = vehicleDef;
size = Mathf.Min(vehicleDef.Size.x, vehicleDef.Size.z);
defaultTerrainImpassable = vehicleDef.properties.defaultTerrainImpassable;
impassableThingDefs = vehicleDef.properties.customThingCosts.Where(kvp => kvp.Value >= VehiclePathGrid.ImpassableCost).Select(kvp => kvp.Key).ToHashSet();
@@ -322,13 +397,11 @@ public VehiclePathData(VehicleDef vehicleDef)
ReachabilityData = null;
}
- public static VehiclePathData Invalid => new VehiclePathData();
-
- public bool IsValid => vehicleDef != null;
+ public bool IsValid => Owner != null;
- public bool UsesRegions => vehicleDef.vehicleMovementPermissions > VehiclePermissions.NotAllowed;
+ public bool UsesRegions => Owner.vehicleMovementPermissions > VehiclePermissions.NotAllowed;
- public VehicleDef Owner => vehicleDef;
+ public VehicleDef Owner { get; }
internal VehicleReachabilitySettings ReachabilityData { get; set; }
@@ -336,17 +409,17 @@ public VehiclePathData(VehicleDef vehicleDef)
public VehiclePathFinder VehiclePathFinder { get; set; }
- public VehicleReachability VehicleReachability => ReachabilityData.vehicleReachability;
+ public VehicleReachability VehicleReachability => ReachabilityData.reachability;
- public VehicleRegionGrid VehicleRegionGrid => ReachabilityData.vehicleRegionGrid;
+ public VehicleRegionGrid VehicleRegionGrid => ReachabilityData.regionGrid;
- public VehicleRegionMaker VehicleRegionMaker => ReachabilityData.vehicleRegionMaker;
+ public VehicleRegionMaker VehicleRegionMaker => ReachabilityData.regionMaker;
- public VehicleRegionLinkDatabase VehicleRegionLinkDatabase => ReachabilityData.vehicleRegionLinkDatabase;
+ public VehicleRegionLinkDatabase VehicleRegionLinkDatabase => ReachabilityData.regionLinkDatabase;
- public VehicleRegionAndRoomUpdater VehicleRegionAndRoomUpdater => ReachabilityData.vehicleRegionAndRoomUpdater;
+ public VehicleRegionAndRoomUpdater VehicleRegionAndRoomUpdater => ReachabilityData.regionAndRoomUpdater;
- public VehicleRegionDirtyer VehicleRegionDirtyer => ReachabilityData.vehicleRegionDirtyer;
+ public VehicleRegionDirtyer VehicleRegionDirtyer => ReachabilityData.regionDirtyer;
public bool MatchesReachability(VehiclePathData other)
{
@@ -359,24 +432,33 @@ public bool MatchesReachability(VehiclePathData other)
}
}
- //Strictly for readability
public class VehicleReachabilitySettings
{
- public VehicleReachability vehicleReachability;
- public VehicleRegionGrid vehicleRegionGrid;
- public VehicleRegionMaker vehicleRegionMaker;
- public VehicleRegionLinkDatabase vehicleRegionLinkDatabase;
- public VehicleRegionAndRoomUpdater vehicleRegionAndRoomUpdater;
- public VehicleRegionDirtyer vehicleRegionDirtyer;
-
- public VehicleReachabilitySettings(VehicleMapping vehicleMapping, VehicleDef vehicleDef)
+ public readonly VehicleRegionGrid regionGrid;
+ public readonly VehicleRegionMaker regionMaker;
+ public readonly VehicleRegionLinkDatabase regionLinkDatabase;
+ public readonly VehicleRegionAndRoomUpdater regionAndRoomUpdater;
+ public readonly VehicleRegionDirtyer regionDirtyer;
+ public readonly VehicleReachability reachability;
+
+ public VehicleReachabilitySettings(VehicleMapping vehicleMapping, VehicleDef vehicleDef, VehiclePathData pathData)
+ {
+ regionGrid = new VehicleRegionGrid(vehicleMapping, vehicleDef);
+ regionMaker = new VehicleRegionMaker(vehicleMapping, vehicleDef);
+ regionLinkDatabase = new VehicleRegionLinkDatabase(vehicleMapping, vehicleDef);
+ regionAndRoomUpdater = new VehicleRegionAndRoomUpdater(vehicleMapping, vehicleDef);
+ regionDirtyer = new VehicleRegionDirtyer(vehicleMapping, vehicleDef);
+ reachability = new VehicleReachability(vehicleMapping, vehicleDef, pathData.VehiclePathGrid, regionGrid);
+ }
+
+ public void PostInit()
{
- vehicleReachability = new VehicleReachability(vehicleMapping, vehicleDef);
- vehicleRegionGrid = new VehicleRegionGrid(vehicleMapping, vehicleDef);
- vehicleRegionMaker = new VehicleRegionMaker(vehicleMapping, vehicleDef);
- vehicleRegionLinkDatabase = new VehicleRegionLinkDatabase();
- vehicleRegionAndRoomUpdater = new VehicleRegionAndRoomUpdater(vehicleMapping, vehicleDef);
- vehicleRegionDirtyer = new VehicleRegionDirtyer(vehicleMapping, vehicleDef);
+ regionGrid.PostInit();
+ regionMaker.PostInit();
+ regionLinkDatabase.PostInit();
+ regionAndRoomUpdater.PostInit();
+ regionDirtyer.PostInit();
+ reachability.PostInit();
}
}
}
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehiclePathGrid.cs b/Source/Vehicles/Pathing/RegionGrid/VehiclePathGrid.cs
index 4f6ac0d5..9af8ed39 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehiclePathGrid.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehiclePathGrid.cs
@@ -28,6 +28,10 @@ public VehiclePathGrid(VehicleMapping mapping, VehicleDef vehicleDef)
ResetPathGrid();
}
+ public void PostInit()
+ {
+ }
+
///
/// Clear path grid of all costs
///
@@ -42,7 +46,16 @@ public void ResetPathGrid()
///
public bool Walkable(IntVec3 loc)
{
- return loc.InBounds(mapping.map) && WalkableFast(loc);
+ try
+ {
+ return loc.InBounds(mapping.map) && WalkableFast(loc);
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Mapping: {mapping is null} Map: {mapping?.map is null} CellInd: {mapping?.map?.cellIndices is null} Info: {mapping?.map?.info}Exception: {ex}");
+ Log.Error($"StackTrace: {StackTraceUtility.ExtractStackTrace()}");
+ }
+ return false;
}
///
@@ -85,7 +98,6 @@ public int PerceivedPathCostAt(IntVec3 loc)
///
/// Recalculate path cost for tile is registered on
///
- ///
public void RecalculatePerceivedPathCostUnderRect(CellRect cellRect, List> snapshotLists)
{
int index = 0;
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleReachability.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleReachability.cs
index b405d0d8..0e58a124 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleReachability.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleReachability.cs
@@ -19,11 +19,8 @@ namespace Vehicles
///
/// Reachability calculator for quick result path finding before running the algorithm
///
- public sealed class VehicleReachability
+ public sealed class VehicleReachability : VehicleRegionManager
{
- private readonly VehicleMapping mapping;
- private readonly VehicleDef createdFor;
-
private readonly Queue openQueue = new Queue();
private readonly AStar chunkSearch;
@@ -34,14 +31,14 @@ public sealed class VehicleReachability
private readonly VehicleReachabilityCache cache = new VehicleReachabilityCache();
- private VehiclePathGrid pathGrid;
- private VehicleRegionGrid regionGrid;
+ private readonly VehiclePathGrid pathGrid;
+ private readonly VehicleRegionGrid regionGrid;
- public VehicleReachability(VehicleMapping mapping, VehicleDef createdFor)
+ public VehicleReachability(VehicleMapping mapping, VehicleDef createdFor, VehiclePathGrid pathGrid, VehicleRegionGrid regionGrid) : base(mapping, createdFor)
{
- this.mapping = mapping;
- this.createdFor = createdFor;
chunkSearch = new AStar(this, mapping, createdFor);
+ this.pathGrid = pathGrid;
+ this.regionGrid = regionGrid;
}
///
@@ -49,31 +46,6 @@ public VehicleReachability(VehicleMapping mapping, VehicleDef createdFor)
///
private bool CalculatingReachability { get; set; }
- public VehiclePathGrid PathGrid
- {
- get
- {
- if (pathGrid is null)
- {
- //Pathgrid is strictly for impassable cost check, so this will still match for copies
- pathGrid = mapping[createdFor].VehiclePathGrid;
- }
- return pathGrid;
- }
- }
-
- public VehicleRegionGrid RegionGrid
- {
- get
- {
- if (regionGrid is null)
- {
- regionGrid = mapping[createdFor].VehicleRegionGrid;
- }
- return regionGrid;
- }
- }
-
///
/// Clear reachability cache
///
@@ -191,7 +163,7 @@ public bool CanReachVehicle(IntVec3 start, LocalTargetInfo dest, PathEndMode peM
return false;
}
- if (!PathGrid.WalkableFast(start))
+ if (!pathGrid.WalkableFast(start))
{
Debug.Message($"Unable to start pathing from {start} to {dest}. Not walkable at {start}");
return false;
@@ -292,9 +264,9 @@ public bool CanReachVehicle(IntVec3 start, LocalTargetInfo dest, PathEndMode peM
private void DetermineStartRegions(IntVec3 start)
{
startingRegions.Clear();
- if (PathGrid.WalkableFast(start))
+ if (pathGrid.WalkableFast(start))
{
- VehicleRegion validRegionAt = RegionGrid.GetValidRegionAt(start);
+ VehicleRegion validRegionAt = regionGrid.GetValidRegionAt(start);
QueueNewOpenRegion(validRegionAt);
startingRegions.Add(validRegionAt);
}
@@ -305,9 +277,9 @@ private void DetermineStartRegions(IntVec3 start)
IntVec3 c = start + GenAdj.AdjacentCells[i];
if (c.InBounds(mapping.map))
{
- if (PathGrid.WalkableFast(c))
+ if (pathGrid.WalkableFast(c))
{
- VehicleRegion validRegionAt = RegionGrid.GetValidRegionAt(c);
+ VehicleRegion validRegionAt = regionGrid.GetValidRegionAt(c);
if (validRegionAt != null && validRegionAt.reachedIndex != reachedIndex)
{
QueueNewOpenRegion(validRegionAt);
@@ -524,7 +496,7 @@ private bool CheckCellBasedReachability(IntVec3 start, LocalTargetInfo dest, Pat
{
if (CanUseCache(traverseParms.mode))
{
- VehicleRegion validRegionAt = RegionGrid.GetValidRegionAt(foundCell);
+ VehicleRegion validRegionAt = regionGrid.GetValidRegionAt(foundCell);
if (!(validRegionAt is null))
{
foreach (VehicleRegion startRegion in startingRegions)
@@ -557,7 +529,7 @@ private bool PassCheck(IntVec3 cell, Map map, TraverseParms traverseParms)
}
if (traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater)
{
- if (!PathGrid.WalkableFast(num))
+ if (!pathGrid.WalkableFast(num))
{
Building edifice = cell.GetEdifice(map);
if (edifice is null || !VehiclePathFinder.IsDestroyable(edifice))
@@ -569,12 +541,12 @@ private bool PassCheck(IntVec3 cell, Map map, TraverseParms traverseParms)
else if (traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater)
{
Log.ErrorOnce("Do not use this method for non-cell based modes!", 938476762);
- if (!PathGrid.WalkableFast(num))
+ if (!pathGrid.WalkableFast(num))
{
return false;
}
}
- VehicleRegion region = RegionGrid.DirectGrid[num];
+ VehicleRegion region = regionGrid.DirectGrid[num];
return region is null || region.Allows(traverseParms, false);
}
@@ -590,7 +562,7 @@ public bool CanReachBase(IntVec3 cell, VehicleDef vehicleDef)
return CanReachVehicle(cell, MapGenerator.PlayerStartSpot, PathEndMode.OnCell, TraverseParms.For(TraverseMode.PassDoors,
Danger.Deadly, false));
}
- if (!GenGridVehicles.Walkable(cell, vehicleDef, mapping.map))
+ if (!GenGridVehicles.Walkable(cell, vehicleDef, mapping))
{
return false;
}
@@ -637,7 +609,7 @@ public bool CanReachBiggestMapEdgeRoom(IntVec3 c)
{
VehicleRoom usableRoom = null;
//ConcurrentDictionary.Keys snapshots, but ConcurrentDictionary.GetEnumerator does not. Must utilize Key or Value collections for thread safe enumeration
- foreach (VehicleRoom room in RegionGrid.allRooms.Keys)
+ foreach (VehicleRoom room in regionGrid.allRooms.Keys)
{
if (room.TouchesMapEdge)
{
@@ -930,7 +902,7 @@ private IEnumerable Neighbors(Node node)
private bool InitRegions(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, out VehicleRegion startingRegion, out VehicleRegion destinationRegion)
{
- startingRegion = vehicleReachability.RegionGrid.GetValidRegionAt(start);
+ startingRegion = vehicleReachability.regionGrid.GetValidRegionAt(start);
destinationRegion = null;
if (startingRegion == null)
{
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleReachabilityUtility.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleReachabilityUtility.cs
index ea6e6844..abd0f74b 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleReachabilityUtility.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleReachabilityUtility.cs
@@ -24,7 +24,7 @@ public static bool CanReachVehicle(this VehiclePawn vehicle, LocalTargetInfo des
{
return true;
}
- return vehicle.Spawned && vehicle.Map.GetCachedMapComponent()[vehicle.VehicleDef].VehicleReachability.CanReachVehicle(vehicle.Position, dest, peMode,
+ return vehicle.Spawned && MapComponentCache.GetComponent(vehicle.Map)[vehicle.VehicleDef].VehicleReachability.CanReachVehicle(vehicle.Position, dest, peMode,
TraverseParms.For(vehicle, maxDanger, mode));
}
@@ -42,7 +42,7 @@ public static bool CanReachVehicleNonLocal(this VehiclePawn vehicle, TargetInfo
{
return true;
}
- return vehicle.Spawned && vehicle.Map.GetCachedMapComponent()[vehicle.VehicleDef].VehicleReachability.CanReachVehicleNonLocal(vehicle.Position, dest, peMode,
+ return vehicle.Spawned && MapComponentCache.GetComponent(vehicle.Map)[vehicle.VehicleDef].VehicleReachability.CanReachVehicleNonLocal(vehicle.Position, dest, peMode,
TraverseParms.For(vehicle, maxDanger, mode));
}
@@ -52,7 +52,7 @@ public static bool CanReachVehicleNonLocal(this VehiclePawn vehicle, TargetInfo
///
public static bool CanReachVehicleMapEdge(this VehiclePawn vehicle)
{
- return vehicle.Spawned && vehicle.Map.GetCachedMapComponent()[vehicle.VehicleDef].VehicleReachability.CanReachMapEdge(vehicle.Position,
+ return vehicle.Spawned && MapComponentCache.GetComponent(vehicle.Map)[vehicle.VehicleDef].VehicleReachability.CanReachMapEdge(vehicle.Position,
TraverseParms.For(vehicle, Danger.Deadly, TraverseMode.ByPawn));
}
@@ -66,7 +66,7 @@ public static void ClearCacheFor(VehiclePawn vehicle)
for (int i = 0; i < maps.Count; i++)
{
maps[i].reachability.ClearCacheFor(vehicle);
- maps[i].GetCachedMapComponent()[vehicle.VehicleDef].VehicleReachability.ClearCacheFor(vehicle);
+ MapComponentCache.GetComponent(maps[i])[vehicle.VehicleDef].VehicleReachability.ClearCacheFor(vehicle);
}
}
}
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleRegion.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleRegion.cs
index ffda634f..e8aa8a39 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleRegion.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleRegion.cs
@@ -32,7 +32,7 @@ public sealed class VehicleRegion
public Building_Door door;
public ConcurrentSet links = new ConcurrentSet();
- public ConcurrentDictionary weights = new ConcurrentDictionary();
+ private Dictionary weights = new Dictionary();
private readonly ConcurrentDictionary cachedDangers = new ConcurrentDictionary();
@@ -57,6 +57,9 @@ public sealed class VehicleRegion
private int debug_makeTick = -1000;
private int debug_lastTraverseTick = -1000;
+ private object weightLock = new object();
+ //private object linkLock = new object();
+
private VehicleRegion(VehicleDef vehicleDef)
{
this.vehicleDef = vehicleDef;
@@ -282,25 +285,39 @@ public void AddLink(VehicleRegionLink regionLink)
public Weight WeightBetween(VehicleRegionLink linkA, VehicleRegionLink linkB)
{
int hash = HashBetween(linkA, linkB);
- if (weights.TryGetValue(hash, out Weight weight))
+ lock (weightLock)
{
- return weight;
+ if (weights.TryGetValue(hash, out Weight weight))
+ {
+ return weight;
+ }
}
Log.Error($"Unable to pull weight between {linkA.anchor} and {linkB.anchor}");
return new Weight(linkA, linkB, 999);
}
+ public void ClearWeights()
+ {
+ lock (weightLock)
+ {
+ weights.Clear();
+ }
+ }
+
public void RecalculateWeights()
{
- weights = new ConcurrentDictionary();
- foreach (VehicleRegionLink regionLink in links.Keys)
+ lock (weightLock)
{
- foreach (VehicleRegionLink connectingToLink in links.Keys)
+ weights.Clear();
+ foreach (VehicleRegionLink regionLink in links.Keys)
{
- if (regionLink == connectingToLink) continue; //Skip matching link
-
- int weight = EuclideanDistance(regionLink.anchor, connectingToLink);
- weights[HashBetween(regionLink, connectingToLink)] = new Weight(regionLink, connectingToLink, weight);
+ foreach (VehicleRegionLink connectingToLink in links.Keys)
+ {
+ if (regionLink == connectingToLink) continue; //Skip matching link
+
+ int weight = EuclideanDistance(regionLink.anchor, connectingToLink);
+ weights[HashBetween(regionLink, connectingToLink)] = new Weight(regionLink, connectingToLink, weight);
+ }
}
}
}
@@ -308,7 +325,7 @@ public void RecalculateWeights()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int HashBetween(VehicleRegionLink linkA, VehicleRegionLink linkB)
{
- return linkA.anchor.GetHashCode() + linkB.anchor.GetHashCode();
+ return Gen.HashCombine(linkA.anchor.GetHashCode(), linkB.anchor);
}
///
@@ -508,31 +525,15 @@ public void DebugDrawMouseover(DebugRegionType debugRegionType)
}
if (debugRegionType.HasFlag(DebugRegionType.Weights))
{
- foreach (VehicleRegionLink regionLink in links.Keys)
- {
- foreach (VehicleRegionLink toRegionLink in links.Keys)
- {
- if (regionLink == toRegionLink) continue;
-
- float weight = weights[HashBetween(regionLink, toRegionLink)].cost;
- Vector3 from = regionLink.anchor.ToVector3();
- from.y += AltitudeLayer.MapDataOverlay.AltitudeFor();
- Vector3 to = toRegionLink.anchor.ToVector3();
- to.y += AltitudeLayer.MapDataOverlay.AltitudeFor();
- GenDraw.DrawLineBetween(from, to, VehicleRegionLink.WeightColor(weight));
- }
- }
-
- foreach (VehicleRegion region in Neighbors)
+ lock (weightLock)
{
foreach (VehicleRegionLink regionLink in links.Keys)
{
- foreach (VehicleRegionLink toRegionLink in region.links.Keys)
+ foreach (VehicleRegionLink toRegionLink in links.Keys)
{
if (regionLink == toRegionLink) continue;
- if (regionLink.RegionA != this && regionLink.RegionB != this) continue;
- float weight = region.weights[HashBetween(regionLink, toRegionLink)].cost;
+ float weight = weights[HashBetween(regionLink, toRegionLink)].cost;
Vector3 from = regionLink.anchor.ToVector3();
from.y += AltitudeLayer.MapDataOverlay.AltitudeFor();
Vector3 to = toRegionLink.anchor.ToVector3();
@@ -540,6 +541,25 @@ public void DebugDrawMouseover(DebugRegionType debugRegionType)
GenDraw.DrawLineBetween(from, to, VehicleRegionLink.WeightColor(weight));
}
}
+
+ foreach (VehicleRegion region in Neighbors)
+ {
+ foreach (VehicleRegionLink regionLink in links.Keys)
+ {
+ foreach (VehicleRegionLink toRegionLink in region.links.Keys)
+ {
+ if (regionLink == toRegionLink) continue;
+ if (regionLink.RegionA != this && regionLink.RegionB != this) continue;
+
+ float weight = region.weights[HashBetween(regionLink, toRegionLink)].cost;
+ Vector3 from = regionLink.anchor.ToVector3();
+ from.y += AltitudeLayer.MapDataOverlay.AltitudeFor();
+ Vector3 to = toRegionLink.anchor.ToVector3();
+ to.y += AltitudeLayer.MapDataOverlay.AltitudeFor();
+ GenDraw.DrawLineBetween(from, to, VehicleRegionLink.WeightColor(weight));
+ }
+ }
+ }
}
}
if (debugRegionType.HasFlag(DebugRegionType.Things))
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionAndRoomUpdater.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionAndRoomUpdater.cs
index 01c66762..aaf21868 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionAndRoomUpdater.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionAndRoomUpdater.cs
@@ -10,24 +10,16 @@ namespace Vehicles
///
/// Region and room update handler
///
- public class VehicleRegionAndRoomUpdater
- {
- private readonly VehicleMapping mapping;
- private readonly VehicleDef createdFor;
-
+ public class VehicleRegionAndRoomUpdater : VehicleRegionManager
+ {
private readonly List newRegions = new List();
private readonly List newRooms = new List();
private readonly HashSet reusedOldRooms = new HashSet();
private readonly List currentRegionGroup = new List();
- private readonly List currentRoomGroup = new List();
-
- private readonly Stack tmpRoomStack = new Stack();
- public VehicleRegionAndRoomUpdater(VehicleMapping mapping, VehicleDef createdFor)
+ public VehicleRegionAndRoomUpdater(VehicleMapping mapping, VehicleDef createdFor) : base(mapping, createdFor)
{
- this.mapping = mapping;
- this.createdFor = createdFor;
}
///
@@ -72,6 +64,7 @@ public void TryRebuildVehicleRegions()
{
return;
}
+
UpdatingRegion = true;
if (!Initialized)
{
@@ -92,7 +85,7 @@ public void TryRebuildVehicleRegions()
Log.Error($"Exception while rebuilding vehicle regions for {createdFor}. Exception={ex}");
}
newRegions.Clear();
- //mapping[createdFor].VehicleRegionDirtyer.SetAllClean();
+ mapping[createdFor].VehicleRegionDirtyer.SetAllClean();
Initialized = true;
UpdatingRegion = false;
}
@@ -103,12 +96,12 @@ public void TryRebuildVehicleRegions()
private void RegenerateNewVehicleRegions()
{
newRegions.Clear();
- var dirtyCells = mapping[createdFor].VehicleRegionDirtyer.DumpDirtyCells();
- foreach (IntVec3 cell in dirtyCells)
+ VehicleMapping.VehiclePathData pathData = mapping[createdFor];
+ foreach (IntVec3 cell in pathData.VehicleRegionDirtyer.DirtyCells)
{
if (VehicleGridsUtility.GetRegion(cell, mapping.map, createdFor, RegionType.Set_All) == null)
{
- VehicleRegion region = mapping[createdFor].VehicleRegionMaker.TryGenerateRegionFrom(cell);
+ VehicleRegion region = pathData.VehicleRegionMaker.TryGenerateRegionFrom(cell);
if (region != null)
{
newRegions.Add(region);
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculator.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculator.cs
index 05b69134..e4ceadd3 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculator.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculator.cs
@@ -24,7 +24,6 @@ public class VehicleRegionCostCalculator
private readonly VehicleMapping mapping;
private readonly VehicleDef vehicleDef;
- private VehicleRegion[] regionGrid;
private ByteGrid avoidGrid;
private TraverseParms traverseParms;
@@ -64,7 +63,6 @@ public VehicleRegionCostCalculator(VehicleMapping mapping, VehicleDef vehicleDef
///
public void Init(CellRect destination, HashSet destRegions, TraverseParms parms, float moveTicksCardinal, float moveTicksDiagonal, ByteGrid avoidGrid, bool drafted)
{
- regionGrid = mapping[vehicleDef].VehicleRegionGrid.DirectGrid;
traverseParms = parms;
destinationCell = destination.CenterCell;
this.moveTicksCardinal = moveTicksCardinal;
@@ -419,7 +417,11 @@ private void GetPreciseRegionLinkDistances(VehicleRegion region, CellRect destin
///
private IEnumerable PreciseRegionLinkDistancesNeighborsGetter(int node, VehicleRegion region)
{
- if (regionGrid[node] is null || regionGrid[node] != region) return null;
+ VehicleRegion[] directGrid = mapping[vehicleDef].VehicleRegionGrid.DirectGrid;
+ if (directGrid == null || directGrid[node] is null || directGrid[node] != region)
+ {
+ return null;
+ }
return PathableNeighborIndices(node);
}
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculatorWrapper.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculatorWrapper.cs
index 58d1f98e..7ff3111a 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculatorWrapper.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionCostCalculatorWrapper.cs
@@ -23,7 +23,6 @@ public class VehicleRegionCostCalculatorWrapper
private VehicleRegionLink cachedSecondBestLink;
private readonly HashSet destRegions = new HashSet();
- private VehicleRegion[] regionGrid;
private int cachedBestLinkCost;
private int cachedSecondBestLinkCost;
@@ -57,7 +56,6 @@ public void Init(CellRect end, TraverseParms traverseParms, float moveTicksCardi
cachedBestLinkCost = 0;
cachedSecondBestLinkCost = 0;
cachedRegionIsDestination = false;
- regionGrid = mapping[vehicleDef].VehicleRegionGrid.DirectGrid;
destRegions.Clear();
if (end.Width == 1 && end.Height == 1)
{
@@ -97,7 +95,7 @@ public void Init(CellRect end, TraverseParms traverseParms, float moveTicksCardi
///
public int GetPathCostFromDestToRegion(int cellIndex)
{
- VehicleRegion region = regionGrid[cellIndex];
+ VehicleRegion region = mapping[vehicleDef].VehicleRegionGrid.DirectGrid[cellIndex];
IntVec3 cell = mapping.map.cellIndices.IndexToCell(cellIndex);
if (region != cachedRegion)
{
diff --git a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionDirtyer.cs b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionDirtyer.cs
index 2e083f10..eb28c825 100644
--- a/Source/Vehicles/Pathing/RegionGrid/VehicleRegionDirtyer.cs
+++ b/Source/Vehicles/Pathing/RegionGrid/VehicleRegionDirtyer.cs
@@ -2,40 +2,43 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
+using System.Runtime.CompilerServices;
using Verse;
using SmashTools;
+using Verse.Noise;
namespace Vehicles
{
///
/// Region dirtyer handler for recaching
///
- public class VehicleRegionDirtyer
- {
- private readonly VehicleMapping mapping;
- private readonly VehicleDef createdFor;
-
- private readonly ConcurrentSet dirtyCells = new ConcurrentSet();
+ public class VehicleRegionDirtyer : VehicleRegionManager
+ {
+ private readonly HashSet