Automatically merge stacks (money, ammo, etc.) when quickly transferring items to containers not marked with a @loot tag
This commit is contained in:
parent
1bee34fc26
commit
545725d380
@ -8,16 +8,18 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
public class ContainerQuickLootPlugin : BaseUnityPlugin
|
public class ContainerQuickLootPlugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
internal static ConfigEntry<bool> EnableForCtrlClick { get; set; }
|
internal static ConfigEntry<bool> EnableForCtrlClick { get; set; }
|
||||||
|
|
||||||
internal static ConfigEntry<bool> EnableForLooseLoot { get; set; }
|
internal static ConfigEntry<bool> EnableForLooseLoot { get; set; }
|
||||||
|
|
||||||
internal static ConfigEntry<bool> AutoMergeStacks { get; set; }
|
internal static ConfigEntry<bool> AutoMergeStacks { get; set; }
|
||||||
|
|
||||||
|
internal static ConfigEntry<bool> AutoMergeStacksForNonLootContainers { get; set; }
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
internal void Start()
|
internal void Start()
|
||||||
{
|
{
|
||||||
const string sectionName = "Container quick loot setting";
|
const string sectionName = "Container quick loot setting";
|
||||||
|
|
||||||
EnableForCtrlClick = Config.Bind
|
EnableForCtrlClick = Config.Bind
|
||||||
(
|
(
|
||||||
sectionName,
|
sectionName,
|
||||||
@ -28,7 +30,7 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
"Automatically put the items in containers while transferring them with ctrl+click"
|
"Automatically put the items in containers while transferring them with ctrl+click"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
EnableForLooseLoot = Config.Bind
|
EnableForLooseLoot = Config.Bind
|
||||||
(
|
(
|
||||||
sectionName,
|
sectionName,
|
||||||
@ -39,7 +41,7 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
"Automatically put loose loot in containers"
|
"Automatically put loose loot in containers"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
AutoMergeStacks = Config.Bind
|
AutoMergeStacks = Config.Bind
|
||||||
(
|
(
|
||||||
sectionName,
|
sectionName,
|
||||||
@ -51,6 +53,18 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
AutoMergeStacksForNonLootContainers = Config.Bind
|
||||||
|
(
|
||||||
|
sectionName,
|
||||||
|
"Merge stacks for non-loot containers",
|
||||||
|
true,
|
||||||
|
new ConfigDescription
|
||||||
|
(
|
||||||
|
"Automatically merge stacks (money, ammo, etc.) when quickly transferring items to " +
|
||||||
|
"containers not marked with a @loot tag"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
new QuickTransferPatch().Enable();
|
new QuickTransferPatch().Enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
public class QuickTransferPatch : ModulePatch
|
public class QuickTransferPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private static readonly Regex LootTagRegex = new Regex("@loot[0-9]*", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100));
|
private static readonly Regex LootTagRegex = new Regex("@loot[0-9]*", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
MethodInfo method = typeof(GClass2585).GetMethod("QuickFindAppropriatePlace", BindingFlags.Public | BindingFlags.Static);
|
MethodInfo method = typeof(GClass2585).GetMethod("QuickFindAppropriatePlace", BindingFlags.Public | BindingFlags.Static);
|
||||||
@ -30,6 +30,8 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
GClass2585.EMoveItemOrder order,
|
GClass2585.EMoveItemOrder order,
|
||||||
bool simulate)
|
bool simulate)
|
||||||
{
|
{
|
||||||
|
Inventory inventory;
|
||||||
|
|
||||||
// If is ctrl+click loot
|
// If is ctrl+click loot
|
||||||
if (order == GClass2585.EMoveItemOrder.MoveToAnotherSide)
|
if (order == GClass2585.EMoveItemOrder.MoveToAnotherSide)
|
||||||
{
|
{
|
||||||
@ -38,51 +40,44 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If is loose loot pick up
|
// If is loose loot pick up
|
||||||
else if (order == GClass2585.EMoveItemOrder.PickUp && controller.OwnerType == EOwnerType.Profile)
|
else if (order == GClass2585.EMoveItemOrder.PickUp && controller.OwnerType == EOwnerType.Profile)
|
||||||
{
|
{
|
||||||
if (!ContainerQuickLootPlugin.EnableForLooseLoot.Value)
|
if (!ContainerQuickLootPlugin.EnableForLooseLoot.Value)
|
||||||
{
|
{
|
||||||
return true;
|
if (!TryGetInventory(out inventory))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !TryMergeItemIntoAnExistingStack(item, inventory, controller, simulate, ref __result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameWorld gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
|
|
||||||
// If gameWorld is null that means the game is currently not in progress, for instance you're in your hideout
|
|
||||||
if (gameWorld == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This check needs to be done only in game - otherwise we will not be able to receive quest rewards!
|
// This check needs to be done only in game - otherwise we will not be able to receive quest rewards!
|
||||||
if (item.QuestItem)
|
if (item.QuestItem)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = GetLocalPlayerFromWorld(gameWorld);
|
if (!TryGetInventory(out inventory))
|
||||||
var inventory = (Inventory)typeof(Player).GetProperty("Inventory", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(player);
|
|
||||||
|
|
||||||
if (inventory == null)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IContainer> targetContainers = FindTargetContainers(item, inventory);
|
IEnumerable<IContainer> targetContainers = FindTargetContainers(item, inventory);
|
||||||
|
|
||||||
foreach (IContainer collectionContainer in targetContainers)
|
foreach (IContainer collectionContainer in targetContainers)
|
||||||
{
|
{
|
||||||
if (!(collectionContainer is GClass2318 container))
|
if (!(collectionContainer is GClass2318 container))
|
||||||
{
|
{
|
||||||
return true;
|
return !TryMergeItemIntoAnExistingStack(item, inventory, controller, simulate, ref __result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once PossibleMultipleEnumeration
|
// ReSharper disable once PossibleMultipleEnumeration
|
||||||
if (!(targets.SingleOrDefaultWithoutException() is EquipmentClass))
|
if (!(targets.SingleOrDefaultWithoutException() is EquipmentClass))
|
||||||
{
|
{
|
||||||
@ -97,18 +92,17 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (containedItem.Key.StackObjectsCount + item.StackObjectsCount > item.StackMaxSize)
|
if (containedItem.Key.StackObjectsCount + item.StackObjectsCount > item.StackMaxSize)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GStruct375<GClass2599> mergeResult = GClass2585.Merge(item, containedItem.Key, controller, simulate);
|
GStruct375<GClass2599> mergeResult = GClass2585.Merge(item, containedItem.Key, controller, simulate);
|
||||||
__result = new GStruct375<GInterface275>(mergeResult.Value);
|
__result = new GStruct375<GInterface275>(mergeResult.Value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GClass2580 location = container.FindLocationForItem(item);
|
GClass2580 location = container.FindLocationForItem(item);
|
||||||
if (location == null)
|
if (location == null)
|
||||||
@ -126,7 +120,32 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
{
|
{
|
||||||
__result = moveResult.Cast<GClass2597, GInterface275>();
|
__result = moveResult.Cast<GClass2597, GInterface275>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !TryMergeItemIntoAnExistingStack(item, inventory, controller, simulate, ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetInventory(out Inventory inventory)
|
||||||
|
{
|
||||||
|
GameWorld gameWorld = Singleton<GameWorld>.Instance;
|
||||||
|
|
||||||
|
// If gameWorld is null that means the game is currently not in progress, for instance you're in your hideout
|
||||||
|
if (gameWorld == null)
|
||||||
|
{
|
||||||
|
inventory = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = GetLocalPlayerFromWorld(gameWorld);
|
||||||
|
|
||||||
|
inventory = (Inventory)typeof(Player)
|
||||||
|
.GetProperty("Inventory", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
|
?.GetValue(player);
|
||||||
|
|
||||||
|
if (inventory == null)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +155,7 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
private static IEnumerable<IContainer> FindTargetContainers(Item item, Inventory inventory)
|
private static IEnumerable<IContainer> FindTargetContainers(Item item, Inventory inventory)
|
||||||
{
|
{
|
||||||
var matchingContainerCollections = new List<(ContainerCollection containerCollection, int priority)>();
|
var matchingContainerCollections = new List<(ContainerCollection containerCollection, int priority)>();
|
||||||
|
|
||||||
foreach (Item inventoryItem in inventory.Equipment.GetAllItems())
|
foreach (Item inventoryItem in inventory.Equipment.GetAllItems())
|
||||||
{
|
{
|
||||||
// It has to be a container collection - an item that we can transfer the loot into
|
// It has to be a container collection - an item that we can transfer the loot into
|
||||||
@ -173,7 +192,7 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
|
|
||||||
string priorityString = regexMatch.Value.Substring(lootTagLength);
|
string priorityString = regexMatch.Value.Substring(lootTagLength);
|
||||||
int priority = priorityString.Length == 0 ? 0 : int.Parse(priorityString);
|
int priority = priorityString.Length == 0 ? 0 : int.Parse(priorityString);
|
||||||
|
|
||||||
matchingContainerCollections.Add((containerCollection, priority));
|
matchingContainerCollections.Add((containerCollection, priority));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +203,45 @@ namespace CactusPie.ContainerQuickLoot
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there are not matching @loot containers found, we will try to merge the item into an existing stack
|
||||||
|
// anyway - but only if this behavior is enabled in the config
|
||||||
|
private static bool TryMergeItemIntoAnExistingStack(
|
||||||
|
Item item,
|
||||||
|
Inventory inventory,
|
||||||
|
TraderControllerClass controller,
|
||||||
|
bool simulate,
|
||||||
|
ref GStruct375<GInterface275> result)
|
||||||
|
{
|
||||||
|
if (!ContainerQuickLootPlugin.AutoMergeStacksForNonLootContainers.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Template.StackMaxSize <= 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Item targetItem in inventory.Equipment.GetAllItems())
|
||||||
|
{
|
||||||
|
if (targetItem.Template._id != item.Template._id)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetItem.StackObjectsCount + item.StackObjectsCount > item.Template.StackMaxSize)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GStruct375<GClass2599> mergeResult = GClass2585.Merge(item, targetItem, controller, simulate);
|
||||||
|
result = new GStruct375<GInterface275>(mergeResult.Value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static Player GetLocalPlayerFromWorld(GameWorld gameWorld)
|
private static Player GetLocalPlayerFromWorld(GameWorld gameWorld)
|
||||||
{
|
{
|
||||||
if (gameWorld == null || gameWorld.MainPlayer == null)
|
if (gameWorld == null || gameWorld.MainPlayer == null)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user