fixes, renames, cleanup

This commit is contained in:
Tyfon
2024-06-17 12:41:42 -07:00
parent 2824f684cc
commit da3ffc170d
7 changed files with 93 additions and 36 deletions

View File

@@ -47,7 +47,7 @@ namespace UIFixes
public static void Clear() public static void Clear()
{ {
// ToList() because we'll be modifying the collection // ToList() because modifying the collection
foreach (GridItemView itemView in SelectedItemViews.Keys.ToList()) foreach (GridItemView itemView in SelectedItemViews.Keys.ToList())
{ {
Deselect(itemView); Deselect(itemView);

View File

@@ -91,31 +91,36 @@ namespace UIFixes
public class CreateSubInteractionsInventoryPatch : ModulePatch public class CreateSubInteractionsInventoryPatch : ModulePatch
{ {
private static bool LoadingInsuranceActions = false;
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
return AccessTools.Method(InventoryRootInteractionsType, "CreateSubInteractions"); return AccessTools.Method(InventoryRootInteractionsType, "CreateSubInteractions");
} }
private static int GetPlayerRubles(ItemUiContext itemUiContext)
{
StashClass stash = itemUiContext.R().InventoryController.Inventory.Stash;
if (stash == null)
{
return 0;
}
return R.Money.GetMoneySums(stash.Grid.ContainedItems.Keys)[ECurrencyType.RUB];
}
[PatchPrefix] [PatchPrefix]
public static bool Prefix(EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, Item ___item_0, ItemUiContext ___itemUiContext_1) public static bool Prefix(EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, Item ___item_0, ItemUiContext ___itemUiContext_1)
{ {
// Clear this, since something else should be active (even a different mouseover of the insurance button)
LoadingInsuranceActions = false;
if (parentInteraction == EItemInfoButton.Insure) if (parentInteraction == EItemInfoButton.Insure)
{ {
int playerRubles = GetPlayerRubles(___itemUiContext_1); int playerRubles = GetPlayerRubles(___itemUiContext_1);
CurrentInsuranceInteractions = new(___item_0, ___itemUiContext_1, playerRubles); CurrentInsuranceInteractions = new(___item_0, ___itemUiContext_1, playerRubles);
CurrentInsuranceInteractions.LoadAsync(() => subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions));
// Because this is async, need to protect against a different subInteractions activating before loading is done
// This isn't thread-safe at all but now the race condition is a microsecond instead of hundreds of milliseconds.
LoadingInsuranceActions = true;
CurrentInsuranceInteractions.LoadAsync(() =>
{
if (LoadingInsuranceActions)
{
subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions);
LoadingInsuranceActions = false;
}
});
return false; return false;
} }
@@ -150,6 +155,8 @@ namespace UIFixes
public class CreateSubInteractionsTradingPatch : ModulePatch public class CreateSubInteractionsTradingPatch : ModulePatch
{ {
private static bool LoadingInsuranceActions = false;
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
return AccessTools.Method(TradingRootInteractionsType, "CreateSubInteractions"); return AccessTools.Method(TradingRootInteractionsType, "CreateSubInteractions");
@@ -158,22 +165,40 @@ namespace UIFixes
[PatchPrefix] [PatchPrefix]
public static bool Prefix(object __instance, EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, ItemUiContext ___itemUiContext_0) public static bool Prefix(object __instance, EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, ItemUiContext ___itemUiContext_0)
{ {
Dictionary<ECurrencyType, int> playerCurrencies = R.Money.GetMoneySums(___itemUiContext_0.R().InventoryController.Inventory.Stash.Grid.ContainedItems.Keys); // Clear this, since something else should be active (even a different mouseover of the insurance button)
int playerRubles = playerCurrencies[ECurrencyType.RUB]; LoadingInsuranceActions = false;
// CreateSubInteractions is only on the base class here, which doesn't have an Item. But __instance is actually a GClass3032
Item item = (Item)TradingRootInteractionsItemField.GetValue(__instance);
if (parentInteraction == EItemInfoButton.Insure) if (parentInteraction == EItemInfoButton.Insure)
{ {
int playerRubles = GetPlayerRubles(___itemUiContext_0);
// CreateSubInteractions is only on the base class here, which doesn't have an Item. But __instance is actually a GClass3032
Item item = (Item)TradingRootInteractionsItemField.GetValue(__instance);
CurrentInsuranceInteractions = new(item, ___itemUiContext_0, playerRubles); CurrentInsuranceInteractions = new(item, ___itemUiContext_0, playerRubles);
CurrentInsuranceInteractions.LoadAsync(() => subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions));
// Because this is async, need to protect against a different subInteractions activating before loading is done
// This isn't thread-safe at all but now the race condition is a microsecond instead of hundreds of milliseconds.
LoadingInsuranceActions = true;
CurrentInsuranceInteractions.LoadAsync(() =>
{
if (LoadingInsuranceActions)
{
subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions);
LoadingInsuranceActions = false;
}
});
return false; return false;
} }
if (parentInteraction == EItemInfoButton.Repair) if (parentInteraction == EItemInfoButton.Repair)
{ {
int playerRubles = GetPlayerRubles(___itemUiContext_0);
// CreateSubInteractions is only on the base class here, which doesn't have an Item. But __instance is actually a GClass3032
Item item = (Item)TradingRootInteractionsItemField.GetValue(__instance);
CurrentRepairInteractions = new(item, ___itemUiContext_0, playerRubles); CurrentRepairInteractions = new(item, ___itemUiContext_0, playerRubles);
subInteractionsWrapper.SetSubInteractions(CurrentRepairInteractions); subInteractionsWrapper.SetSubInteractions(CurrentRepairInteractions);
@@ -276,5 +301,16 @@ namespace UIFixes
return true; return true;
} }
} }
private static int GetPlayerRubles(ItemUiContext itemUiContext)
{
StashClass stash = itemUiContext.R().InventoryController.Inventory.Stash;
if (stash == null)
{
return 0;
}
return R.Money.GetMoneySums(stash.Grid.ContainedItems.Keys)[ECurrencyType.RUB];
}
} }
} }

View File

@@ -113,7 +113,7 @@ namespace UIFixes
return; return;
} }
// Restore scroll position now that the we're loaded // Restore scroll position now that offers are loaded
if (History.Any()) if (History.Any())
{ {
offerViewList.R().Scroller.SetScrollPosition(History.Peek().scrollPosition); offerViewList.R().Scroller.SetScrollPosition(History.Peek().scrollPosition);
@@ -239,7 +239,7 @@ namespace UIFixes
newRule.SortType = filterRule.SortType; newRule.SortType = filterRule.SortType;
newRule.SortDirection = filterRule.SortDirection; newRule.SortDirection = filterRule.SortDirection;
// We can't set handbookId yet - it limits the result set and that in turn limits what categories even display // Can't set handbookId yet - it limits the result set and that in turn limits what categories even display
DelayedHandbookId = filterRule.HandbookId; DelayedHandbookId = filterRule.HandbookId;
ragfair.SetFilterRule(newRule, true, true); ragfair.SetFilterRule(newRule, true, true);
@@ -339,7 +339,7 @@ namespace UIFixes
return AccessTools.Method(typeof(OfferViewList), nameof(OfferViewList.method_10)); return AccessTools.Method(typeof(OfferViewList), nameof(OfferViewList.method_10));
} }
// The firs thing this method does is set scrollposition to 0, so we need to grab it first // The first thing this method does is set scrollposition to 0, so grab it first
[PatchPrefix] [PatchPrefix]
public static void Prefix(LightScroller ____scroller) public static void Prefix(LightScroller ____scroller)
{ {

View File

@@ -72,7 +72,7 @@ namespace UIFixes
inventoryController.LoadMagazine(bullets, magazine, count, false).HandleExceptions(); inventoryController.LoadMagazine(bullets, magazine, count, false).HandleExceptions();
} }
// The calling code in this instance doesn't do anything with the task, but it does await it, so if we don't return a Task it nullrefs // The calling code in this instance doesn't do anything with the task, but it does await it, so if this doesn't return a Task it nullrefs
__result = Task.CompletedTask; __result = Task.CompletedTask;
return false; return false;
} }

View File

@@ -240,7 +240,7 @@ namespace UIFixes
} }
[PatchPrefix] [PatchPrefix]
public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result) public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result, ItemUiContext ___itemUiContext_0)
{ {
if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active) if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{ {
@@ -311,6 +311,12 @@ namespace UIFixes
} }
else else
{ {
// Wrap this error to display it
if (operation.Error is GClass3292 noRoomError)
{
operation = new(new DisplayableErrorWrapper(noRoomError));
}
break; break;
} }
@@ -326,7 +332,7 @@ namespace UIFixes
HidePreviews(); HidePreviews();
} }
// We didn't simulate so now we undo // Didn't simulate so now undo
while (operations.Any()) while (operations.Any())
{ {
operations.Pop().Value?.RollBack(); operations.Pop().Value?.RollBack();
@@ -335,6 +341,21 @@ namespace UIFixes
// result and operation are set to the last one that completed - so success if they all passed, or the first failure // result and operation are set to the last one that completed - so success if they all passed, or the first failure
return false; return false;
} }
// GridView.HighlightItemViewPosition has a blacklist of errors it won't show, but it shows other types.
// Wrapping an error can get past that
private class DisplayableErrorWrapper(InventoryError error) : InventoryError
{
public override string ToString()
{
return error.ToString();
}
public override string GetLocalizedDescription()
{
return error.GetLocalizedDescription();
}
}
} }
public class GridViewAcceptItemPatch : ModulePatch public class GridViewAcceptItemPatch : ModulePatch
@@ -470,7 +491,7 @@ namespace UIFixes
} }
[PatchPrefix] [PatchPrefix]
public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result, InventoryControllerClass ___InventoryController) public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result, InventoryControllerClass ___InventoryController, ItemUiContext ___ItemUiContext)
{ {
if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active) if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{ {
@@ -500,7 +521,7 @@ namespace UIFixes
} }
} }
// We didn't simulate so now we undo // Didn't simulate so now undo
while (operations.Any()) while (operations.Any())
{ {
operations.Pop().Value?.RollBack(); operations.Pop().Value?.RollBack();
@@ -599,7 +620,7 @@ namespace UIFixes
HidePreviews(); HidePreviews();
} }
// We didn't simulate so now we undo // Didn't simulate so now undo
while (operations.Any()) while (operations.Any())
{ {
operations.Pop().Value?.RollBack(); operations.Pop().Value?.RollBack();
@@ -631,7 +652,7 @@ namespace UIFixes
traderAssortmentController.PrepareToSell(itemContext.Item, locationInGrid); traderAssortmentController.PrepareToSell(itemContext.Item, locationInGrid);
itemContext.CloseDependentWindows(); itemContext.CloseDependentWindows();
// For the rest of the items we still need to use quickfind // For the rest of the items, still need to use quickfind
foreach (ItemContextClass selectedItemContext in MultiSelect.ItemContexts.Where(ic => ic.Item != itemContext.Item)) foreach (ItemContextClass selectedItemContext in MultiSelect.ItemContexts.Where(ic => ic.Item != itemContext.Item))
{ {
GStruct413 operation = InteractionsHandlerClass.QuickFindAppropriatePlace(selectedItemContext.Item, traderAssortmentController.TraderController, [__instance.Grid.ParentItem as LootItemClass], InteractionsHandlerClass.EMoveItemOrder.Apply, true); GStruct413 operation = InteractionsHandlerClass.QuickFindAppropriatePlace(selectedItemContext.Item, traderAssortmentController.TraderController, [__instance.Grid.ParentItem as LootItemClass], InteractionsHandlerClass.EMoveItemOrder.Apply, true);

View File

@@ -15,10 +15,10 @@ namespace UIFixes
{ {
public static class SwapPatches public static class SwapPatches
{ {
// Source container for the drag - we have to grab this early to check it // Source container for the drag - grab this early to check it
private static IContainer SourceContainer; private static IContainer SourceContainer;
// Whether we're being called from the "check every slot" loop // Whether it's being called from the "check every slot" loop
private static bool InHighlight = false; private static bool InHighlight = false;
// The most recent CheckItemFilter result - needed to differentiate "No room" from incompatible // The most recent CheckItemFilter result - needed to differentiate "No room" from incompatible
@@ -237,7 +237,7 @@ namespace UIFixes
// This is the location you're dragging it, including rotation // This is the location you're dragging it, including rotation
LocationInGrid itemToLocation = __instance.CalculateItemLocation(itemContext); LocationInGrid itemToLocation = __instance.CalculateItemLocation(itemContext);
// Target is a grid because we're in the GridView patch, i.e. you're dragging it over a grid // Target is a grid because this is the GridView patch, i.e. you're dragging it over a grid
var targetGridItemAddress = new R.GridItemAddress(targetItemAddress); var targetGridItemAddress = new R.GridItemAddress(targetItemAddress);
ItemAddress itemToAddress = R.GridItemAddress.Create(targetGridItemAddress.Grid, itemToLocation); ItemAddress itemToAddress = R.GridItemAddress.Create(targetGridItemAddress.Grid, itemToLocation);
@@ -276,7 +276,7 @@ namespace UIFixes
} }
} }
// If we're coming from a grid, try rotating the target object // If coming from a grid, try rotating the target object
if (R.GridItemAddress.Type.IsInstanceOfType(itemAddress)) if (R.GridItemAddress.Type.IsInstanceOfType(itemAddress))
{ {
var targetToLocation = new R.GridItemAddress(targetToAddress).LocationInGrid; var targetToLocation = new R.GridItemAddress(targetToAddress).LocationInGrid;
@@ -286,7 +286,7 @@ namespace UIFixes
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, traderControllerClass, true); var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, traderControllerClass, true);
if (result.Succeeded) if (result.Succeeded)
{ {
// Only save this operation result if it succeeded, otherwise we return the non-rotated result from above // Only save this operation result if it succeeded, otherwise return the non-rotated result from above
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation(); operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
__result = true; __result = true;
return; return;
@@ -443,7 +443,7 @@ namespace UIFixes
} }
// CanApply, when dealing with containers, eventually calls down into FindPlaceForItem, which calls CheckItemFilter. For reasons, // CanApply, when dealing with containers, eventually calls down into FindPlaceForItem, which calls CheckItemFilter. For reasons,
// if an item fails the filters, it returns the error "no space", instead of "no action". Try to detect this, so we can swap. // if an item fails the filters, it returns the error "no space", instead of "no action". Try to detect this in order to swap.
public class DetectFilterForSwapPatch : ModulePatch public class DetectFilterForSwapPatch : ModulePatch
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
@@ -461,7 +461,7 @@ namespace UIFixes
} }
// When dragging an item around, by default it updates an ItemSpecificationPanel when you drag an item on top of a slot // When dragging an item around, by default it updates an ItemSpecificationPanel when you drag an item on top of a slot
// It doesn't do anything when you drag an item from a slot onto some other item elsewhere. But with swap, we should update the item panel then too. // It doesn't do anything when you drag an item from a slot onto some other item elsewhere. But with swap, update the item panel then too.
public class InspectWindowUpdateStatsOnSwapPatch : ModulePatch public class InspectWindowUpdateStatsOnSwapPatch : ModulePatch
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()