Skip to content

Commit

Permalink
Merge branch 'cache' - good luck out there
Browse files Browse the repository at this point in the history
  • Loading branch information
lilwhitemouse committed Apr 20, 2024
2 parents d0616ad + a8ed199 commit 9be736e
Show file tree
Hide file tree
Showing 36 changed files with 1,337 additions and 157 deletions.
171 changes: 99 additions & 72 deletions DeepStorage/CompDeepStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,14 @@

namespace LWM.DeepStorage
{
public class CompDeepStorage : ThingComp, IHoldMultipleThings.IHoldMultipleThings {
//public float y=0f;
public class CompDeepStorage : ThingComp, IExposable, IHoldMultipleThings.IHoldMultipleThings {
public override IEnumerable<Gizmo> CompGetGizmosExtra() {
foreach (Gizmo g in base.CompGetGizmosExtra()) {
yield return g;
}
#if DEBUGLWM
yield return new Command_Action
{
// icon = has_Ideology?UI/Abilities/WorkDrive :
icon = ContentFinder<Texture2D>.Get("Things/Mote/Thought", true),
// icon = ContentFinder<Texture2D>.Get("UI/Commands/RenameZone", true),
// icon = ContentFinder<Texture2D>.Get("Things/Item/Unfinished/UnfinishedGun", true),
defaultLabel = "Settings".Translate(),
action = delegate()
{
Find.WindowStack.Add(new Dialog_CompSettings(this));
}
};
#else
yield return new Command_Action // Rename
{
icon = ContentFinder<Texture2D>.Get("UI/Commands/RenameZone", true),
defaultLabel = "CommandRenameZoneLabel".Translate(),
action = delegate()
{
Find.WindowStack.Add(new Dialog_RenameDSU(this));
},
hotKey = KeyBindingDefOf.Misc1
};
#endif
foreach (Gizmo g in DSStorageGroupUtility.GetDSStorageGizmos())
yield return g;

#if DEBUG
yield return new Command_Toggle {
defaultLabel="Use RClick Logic",
Expand Down Expand Up @@ -124,28 +101,6 @@ public override string CompInspectStringExtra() {
return origLabel;
}

public int MinNumberStacks {
get {
return ((Properties)this.props).minNumberStacks;
}
}
public int MaxNumberStacks {
get {
return maxNumberStacks ?? ((Properties)this.props).maxNumberStacks;
//return ((Properties)this.props).maxNumberStacks;
}
[Multiplayer.API.SyncMethod]
set {
this.maxNumberStacks = value;
}
}

[Multiplayer.API.SyncMethod]
public virtual void ResetSettings()
{
this.maxNumberStacks = null;
}

public virtual int TimeStoringTakes(Map map, IntVec3 cell, Pawn pawn) {
if (CdsProps.minTimeStoringTakes <0) {
// Basic version
Expand Down Expand Up @@ -215,24 +170,10 @@ public virtual int TimeStoringTakes(Map map, IntVec3 cell, Pawn pawn) {
return t;
} // end TimeStoringTakes

public virtual bool ShowContents
{
get {
return ((Properties)this.props).showContents;
}
}

public Properties CdsProps // b/c I hate typing :p
{
get {
return ((Properties)this.props);
}
}

public override void Initialize(CompProperties props) {
base.Initialize(props);
/******* Initialize local variables *******/
this.maxNumberStacks = CdsProps.maxNumberStacks;
//this.maxNumberStacks = CdsProps.maxNumberStacks; //null->use CdsProps!

/******* For only one limiting stat: (mass, or bulk for CombatExtended) *******/
if (((Properties)props).altStat != null) stat = ((Properties)props).altStat;
Expand All @@ -251,11 +192,25 @@ public override void Initialize(CompProperties props) {
}
*/
}
// Tell the DSMapComponent that something has changed and any storage info for the
// unit may now be incorrect
public void DirtyMapCache()
{
if (parent is Building_Storage && parent.Spawned)
{
MapComponentDS dsm = parent.Map.GetComponent<MapComponentDS>();
foreach (var cell in (parent as Building_Storage).AllSlotCells())
dsm.DirtyCache(cell);
}
}

// IMPORTANT NOTE: some of the following logic is in the patch for TryFindBestBetterStoreCellFor
// (ShouldRemoveFrom logic). TODO: it should probably be here

public virtual int CapacityToStoreThingAt(Thing thing, Map map, IntVec3 cell) {
return map.GetComponent<MapComponentDS>().CapacityToStoreItemAt(this, thing, cell);
}
public virtual int CapacityToStoreThingAtDirect(Thing thing, Map map, IntVec3 cell) {
Utils.Warn(CheckCapacity, "Checking Capacity to store "+thing.stackCount+thing+" at "
+(map?.ToString()??"NULL MAP")+" "+cell);
int capacity = 0;
Expand Down Expand Up @@ -294,7 +249,7 @@ public virtual int CapacityToStoreThingAt(Thing thing, Map map, IntVec3 cell) {
Utils.Warn(CheckCapacity, " But all stacks already taken: "+(stacksStoredHere-1)+" / "+MaxNumberStacks);
return 0;
}
return thing.stackCount;
return thing.stackCount;//todo: wrong? mass?
}
if (thingInStorage.CanStackWith(thing)) {
if (thingInStorage.stackCount < thingInStorage.def.stackLimit) {
Expand Down Expand Up @@ -342,32 +297,104 @@ public virtual int CapacityToStoreThingAt(Thing thing, Map map, IntVec3 cell) {
}
/************************** IHoldMultipleThings interface ************************/
/* For compatibility with Mehni's PickUpAndHaul */
/* (Note: without mass-limits factored in, 1.4's vanilla code handles everything *
* without deep storage having to do a thing! */
// NOTE: Maybe for Multiplayer makes sense to patch this?
public bool CapacityAt(Thing thing, IntVec3 cell, Map map, out int capacity) {
capacity = this.CapacityToStoreThingAt(thing, map, cell);
capacity = map.GetComponent<MapComponentDS>().CapacityToStoreItemAt(this, thing, cell);
// capacity = this.CapacityToStoreThingAt(thing, map, cell);
if (capacity > 0) return true;
return false;
}
// (I still think this is a stupid name)
public bool StackableAt(Thing thing, IntVec3 cell, Map map) {
return this.CapacityToStoreThingAt(thing,map,cell) > 0;
return map.GetComponent<MapComponentDS>().CanStoreItemAt(this, thing, cell);
//return this.CapacityToStoreThingAt(thing,map,cell) > 0;
}
/*********************************************************************************/
public override void PostExposeData() { // why not call it "ExposeData" anyway?
Scribe_Values.Look<string>(ref buildingLabel, "LWM_DS_DSU_label", "", false);
Scribe_Values.Look<int?>(ref maxNumberStacks, "LWM_DS_DSU_maxNumberStacks", null, false);
}
public void ExposeData() // Because ExposeData is a special IExposable thing!
{
PostExposeData();
}
/********************** properties **********************/
public Properties CdsProps // b/c I hate typing :p
{
get {
return ((Properties)this.props);
}
}
public int MinNumberStacks
{
get {
return ((Properties)this.props).minNumberStacks;
}
}
public int MaxNumberStacks
{
get {
return maxNumberStacks ?? ((Properties)this.props).maxNumberStacks;
}
set {
int? newValue = (value == CdsProps.maxNumberStacks ? (int?)null : (int?)value);
if ((parent is IStorageGroupMember storage) && storage.Group != null)
{
foreach (var c in DSStorageGroupUtility.GetDSCompsFromGroup(storage.Group))
{
c.SetMaxNumberStacksDirect(newValue);
}
}
else SetMaxNumberStacksDirect(newValue);
}
}
[Multiplayer.API.SyncMethod]
public void SetMaxNumberStacksDirect(int? n)
{
this.maxNumberStacks = n;
this.DirtyMapCache();
}

public virtual bool ShowContents
{
get {
return ((Properties)this.props).showContents;
}
}

public void SetLabel(string newLabel)
{
if (newLabel == null) buildingLabel = "";
else buildingLabel = newLabel;
SetLabelMultiplayer(buildingLabel);
if (newLabel == null) newLabel = "";
if ((parent is IStorageGroupMember storage) && storage.Group != null)
{
foreach (var c in DSStorageGroupUtility.GetDSCompsFromGroup(storage.Group)) {
c.SetLabelDirect(newLabel);
}
}
else SetLabelDirect(newLabel);
}
[Multiplayer.API.SyncMethod] // I am informed that doing it this way is overkill
private void SetLabelMultiplayer(string newLabel)
[Multiplayer.API.SyncMethod]
private void SetLabelDirect(string newLabel)
{
buildingLabel = newLabel;
}

[Multiplayer.API.SyncMethod]
public virtual void ResetSettings()
{
this.buildingLabel = "";
this.maxNumberStacks = null;
this.DirtyMapCache();
}

public void CopySettingsFrom(CompDeepStorage other)
{
SetLabelDirect(other.buildingLabel);
SetMaxNumberStacksDirect(other.maxNumberStacks);
}

public string buildingLabel="";

/////////////// Storage Data ////////////////
Expand Down
2 changes: 1 addition & 1 deletion DeepStorage/CompProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public enum GuiOverlayType : byte {
CountOfStacksPerCell, // Standard overlay position for each cell
SumOfAllItems, // Centered on DSU
SumOfItemsPerCell, // For e.g., Big Shelf
None, // Some users may want this
None, // Some users definitely want this
}

}
62 changes: 61 additions & 1 deletion DeepStorage/Deep_Storage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,64 @@
/// 9. ModCompatibility.cs
/// Makes Deep Storage play well with:
/// RimWorld Search Agency (Hauling Hysteresis)
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////


//////////////////// Storage Groups /////////////////////
///// General Groups /////
Vanilla:
The StorageGroup has a set of StorageSettings that get returned when the linked storage building
is queried.
But:
Our CompDeepStorage is specific to the building, not to the group: different qualities might have
different abilities, etc :/ (I.e., more storage capacity for Excellent)
General idea: don't try linking things, just copy all DS settings when a link is made, and if any DS
settings actually change, make the change to all members. This is definitely differeint from how
vanilla does it, but it will be easier for me, because it's harder to miss any places the groups
might be important, and I KNOW all the places the DS settings change.
///// Buildings Storage /////
Patch Building_Storage's IStorageGroupMember.SetStorageGroup directly to get settings from any other
members of the group (if there is one)
///// Blueprints ///// Blueprint_Storage
Keep the StorageGroup information in the MapComponent
Joining Group: Patch Blueprint_Storage's IStorageGroupMember.SetStorageGroup to get any settings
and store them in the mapcomponent
-> Frame:
Patch Blueprint_Storage's MakeSolidThing
Destroyed: Patch Blueprint_Storage Destroy(...)
gizmos
///// Frames ///// Frame
CompleteConstruction - will need a transpile: match somewhere in:
IStorageGroupMember storageGroupMember;
if ((storageGroupMember = (thing as IStorageGroupMember)) != null)
{
storageGroupMember.SetStorageGroup(this.storageGroup);
}
Building_Storage building_Storage;
if ((building_Storage = (thing as Building_Storage)) != null /*Prolly here*/ && this.storageSettings != null)
{
building_Storage.settings.CopyFrom(this.storageSettings);
}
FailConstruction - will need a transpile: similar to above
SetStorageGroup - same as for blueprint?
Destroy() remove from mapcomponent
GetGizmos - ? do we care?

PROBLEM: Vanilla has an edge case bug:
Build two shelves and one blueprint. Link them all. Turn the blueprint into a Frame.
Save game here for showing bug.
Change a setting in either Shelf - we would expect this to propagate across all storage group members,
and it does to the other shelf. Unlink one of the shelves(!) This destroys the group because technically
it only has two members and just lost one.
Path 1: Save the game... Finish building Frame->Shelf. The Shelf does not have the propaged settings.
(It's still pulling them from the Storage Settings object that it alone links to now)
Path 2: Do not save the game... Finish building the Frame->Shelf. The Shelf DOES have the propagated settings.
(The Storage Settings object was never saved)



NOTE: Probably a better choice:
Have a new class CompSettings.cs, which gets saved somehow and multiple things can point to it. It's not as straightforward
in a lot ways, but in other ways, will mirror Vanilla very well


13 changes: 7 additions & 6 deletions DeepStorage/Deep_Storage_CanCarryItemsTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace LWM.DeepStorage
**************************************/
//todo1.4: OMG, this all goes away:D
//todo1.4 [HarmonyPatch(typeof(RimWorld.StoreUtility), "NoStorageBlockersIn")]
class Patch_NoStorageBlockersIn {
class Patch_NoStorageBlockersInXXX {
protected static bool Prefix(IntVec3 c, Map map, Thing thing, ref bool __result) {
Utils.Err(NoStorageBlockerseIn, "Looking for blockers for " + thing + " at " + c);
// Check if storage location is in an uber-storage building:
Expand Down Expand Up @@ -253,15 +253,16 @@ static bool Prepare(Harmony instance)
static void Postfix(ref bool __result, IntVec3 c, Map map, Pawn carrier)
{
if (__result == false) return;
if (specialTest != null && specialTest(carrier)) return; // passes specialTest?
if (carrier?.RaceProps == null) return;
if (carrier.RaceProps.intelligence >= NecessaryIntelligenceToUseDeepStorage)
return; // smart enough to use whatever.
// okay, potentially need to see if we're looking at deep storage after all:
// Check if deep storage restrictions even apply here - if it's to a regular shelf,
// or to a stockpile, for example, we shouldn't be futzing with it:
if (LWM.DeepStorage.Utils.CanStoreMoreThanOneThingAt(map, c))
{
__result = false;
}
if (specialTest != null && specialTest(carrier)) return; // passes specialTest?
if (carrier?.RaceProps == null) return;
if (carrier.RaceProps.intelligence >= NecessaryIntelligenceToUseDeepStorage)
return; // smart enough to use whatever.
return;
}
}
Expand Down
11 changes: 9 additions & 2 deletions DeepStorage/Deep_Storage_Display.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,16 @@ static public List<Thing> ThingListToDisplay(Map map, IntVec3 loc) {
// Making item on top display on top: loaded items on "top" need to go into the HashSet
// Gui Overlay: loaded items' overlays should not display
// Put DeepStorage at the end of the ThingsList for proper display post-save
// WARNING: This includes code to dirty the cache
// TODO: Refactor and clean this up
[HarmonyPatch(typeof(Building_Storage), "SpawnSetup")]
public static class PatchDisplay_SpawnSetup {
public static void Postfix(Building_Storage __instance, Map map) {
public static void Postfix(Building_Storage __instance, Map map, bool respawningAfterLoad) {
CompDeepStorage cds;
if ((cds = __instance.GetComp<CompDeepStorage>()) == null) return;

foreach (IntVec3 cell in __instance.AllSlotCells()) {
if (!respawningAfterLoad) map.GetComponent<MapComponentDS>().DirtyCache(cell);

List<Thing> list = map.thingGrid.ThingsListAt(cell);
bool alreadyFoundItemOnTop=false;
for (int i=list.Count-1; i>=0; i--) {
Expand Down Expand Up @@ -248,6 +251,7 @@ public static void Postfix(Building_Storage __instance,Thing newItem) {
// Notify_LostThing is an empty declaration, and it seems to be optimized out of existance,
// so Harmony cannot attach to it. The game crashes - with no warning - when the patched
// method gets called.
// NOTE: by RimWorld 1.4, Harmony and RW are playing well together, and this would work now:
#if false
[HarmonyPatch(typeof(RimWorld.Building_Storage), "Notify_LostThing")]
public static class PatchDisplay_Notify_LostThing {
Expand Down Expand Up @@ -296,6 +300,8 @@ static void Prefix(Thing __instance) {
}

/*************** Deep Storage DeSpawns (destroyed, minified, etc) *****************/
/*WARNING: This includes code to handle dirtying cache
* TODO: Refactor and clean this up */
[HarmonyPatch(typeof(Verse.Building), "DeSpawn")]
public static class Patch_Building_DeSpawn_For_Building_Storage {
[HarmonyPriority(Priority.First)] // MUST execute, cannot be postfix,
Expand All @@ -316,6 +322,7 @@ public static void Prefix(Building __instance) {
return;
}
foreach (IntVec3 cell in DSU.AllSlotCells()) {
__instance.Map.GetComponent<MapComponentDS>().DirtyCache(cell);
List<Thing> list = map.thingGrid.ThingsListAt(cell);
Thing t;
for (int i=0; i<list.Count;i++) {
Expand Down
Loading

0 comments on commit 9be736e

Please sign in to comment.