281 lines
10 KiB
C#
281 lines
10 KiB
C#
using JetBrains.Annotations;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Rebirth.RemoteCrafting
|
|
{
|
|
[UsedImplicitly]
|
|
public class RemoteCraftingUtils
|
|
{
|
|
public static List<TileEntity> GetTileEntities(EntityAlive player)
|
|
{
|
|
var distance = 150f;
|
|
|
|
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
|
|
return tileEntities;
|
|
}
|
|
|
|
public static bool DisableSender(IEnumerable<string> value, TileEntity tileEntity)
|
|
{
|
|
if (tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage))
|
|
{
|
|
if (value.All(x => x.Trim() != storage.lootListName))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool BindToWorkstation(string value, EntityAlive player, TileEntity tileEntity)
|
|
{
|
|
var result = false;
|
|
if (player is not EntityPlayerLocal playerLocal) return false;
|
|
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) return false;
|
|
|
|
// TODO: we want to refactor this to remove the complex LinQ.
|
|
|
|
// what could be easier than linq?
|
|
|
|
// bind storage to workstation
|
|
if (value.Split(';').Where(x =>
|
|
x.Split(':')[0].Split(',').Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation))
|
|
.Any(x => x.Split(':')[1].Split(',').Any(y => y == storage.lootListName))) result = true;
|
|
// bind storage to other workstations if allowed
|
|
if (value.Split(';').Any(x =>
|
|
x.Split(':')[0].Split(',').Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation)))
|
|
return result;
|
|
{
|
|
if (value.Split(';').Any(x => x.Split(':')[1].Split(',').Any(y => y == storage.lootListName)))
|
|
{
|
|
result = false;
|
|
}
|
|
else
|
|
{
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static bool NotToWorkstation(string value, EntityAlive player, TileEntity tileEntity)
|
|
{
|
|
var result = false;
|
|
if (player is not EntityPlayerLocal playerLocal) return false;
|
|
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) return false;
|
|
|
|
foreach (var bind in value.Split(';'))
|
|
{
|
|
var workstation = bind.Split(':')[0].Split(',');
|
|
var disablebinding = bind.Split(':')[1].Split(',');
|
|
if ((workstation.Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation)) &&
|
|
(disablebinding.Any(x => x.Trim() == storage.lootListName))) result = true;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static List<ItemStack> SearchNearbyContainers(EntityAlive player)
|
|
{
|
|
var items = new List<ItemStack>();
|
|
var tileEntities = GetTileEntities(player);
|
|
foreach (var tileEntity in tileEntities)
|
|
{
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
|
|
|
|
if (storage.IsUserAccessing()) continue;
|
|
|
|
items.AddRange(storage.items);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
public static List<ItemStack> SearchNearbyContainers(EntityAlive player, ItemValue itemValue)
|
|
{
|
|
var item = new List<ItemStack>();
|
|
var items = new List<ItemStack>();
|
|
var tileEntities = GetTileEntities(player);
|
|
foreach (var tileEntity in tileEntities)
|
|
{
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
|
|
|
|
// If the container is open, don't use it.
|
|
if (storage.IsUserAccessing()) continue;
|
|
|
|
item.AddRange(storage.items);
|
|
}
|
|
|
|
foreach (var t in item)
|
|
{
|
|
if ((!t.itemValue.HasModSlots || !t.itemValue.HasMods()) &&
|
|
t.itemValue.type == itemValue.type)
|
|
{
|
|
items.Add(t);
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
public static List<ItemStack> SearchNearbyContainers(EntityAlive player, ItemValue itemValue, float distance)
|
|
{
|
|
var item = new List<ItemStack>();
|
|
var items = new List<ItemStack>();
|
|
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
|
|
foreach (var tileEntity in tileEntities)
|
|
{
|
|
if (tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage))
|
|
{
|
|
if (storage.IsUserAccessing()) continue;
|
|
|
|
item.AddRange(storage.items);
|
|
}
|
|
}
|
|
|
|
foreach (var t in item)
|
|
{
|
|
if ((!t.itemValue.HasModSlots || !t.itemValue.HasMods()) &&
|
|
t.itemValue.type == itemValue.type)
|
|
{
|
|
items.Add(t);
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
public static bool AddToNearbyContainer(EntityAlive player, ItemStack itemStack, float distance)
|
|
{
|
|
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
|
|
foreach (var tileEntity in tileEntities)
|
|
{
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
|
|
|
|
// If the container is open, don't include it.
|
|
if (storage.IsUserAccessing()) continue;
|
|
|
|
// Don't try to add to a drop box.
|
|
if (storage.blockValue.Block.Properties.Values.ContainsKey("DropBox")) continue;
|
|
|
|
// Can we quickly find a incomplete stack?
|
|
//if (lootTileEntity.TryStackItem(0, itemStack)) return true;
|
|
var result = storage.TryStackItem(0, itemStack);
|
|
if (result.allMoved) return true;
|
|
|
|
var matchingItem = false;
|
|
// Loop through the items and see if we have any matching items.
|
|
foreach (var item in storage.items)
|
|
{
|
|
// We match with something.
|
|
if (item.itemValue.type != itemStack.itemValue.type) continue;
|
|
|
|
matchingItem = true;
|
|
break;
|
|
}
|
|
|
|
// If we don't match, don't try to add.
|
|
if (!matchingItem) continue;
|
|
|
|
// We added a full stack! No need to keep processing.
|
|
if (storage.AddItem(itemStack)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void ConsumeItem(IEnumerable<ItemStack> itemStacks, EntityPlayerLocal localPlayer, int multiplier, IList<ItemStack> _removedItems, Bag bag, Inventory toolbelt)
|
|
{
|
|
var tileEntities = GetTileEntities(localPlayer);
|
|
var enumerable = itemStacks as ItemStack[] ?? itemStacks.ToArray();
|
|
for (var i = 0; i < enumerable.Count(); i++)
|
|
{
|
|
// Grab from the backpack first.
|
|
var num = enumerable[i].count * multiplier;
|
|
if (bag != null)
|
|
{
|
|
num -= bag.DecItem(enumerable[i].itemValue, num, true, _removedItems);
|
|
if (num > 0)
|
|
{
|
|
// Check tool belt
|
|
if (toolbelt != null)
|
|
{
|
|
num -= toolbelt.DecItem(enumerable[i].itemValue, num, true, _removedItems);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We've met our goals for this.
|
|
if (num <= 0) continue;
|
|
|
|
// check storage boxes
|
|
foreach (var tileEntity in tileEntities)
|
|
{
|
|
if (num <= 0) break;
|
|
|
|
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
|
|
|
|
// If someone is using the tool account, skip it.
|
|
if (storage.IsUserAccessing()) continue;
|
|
|
|
// If there's no items in this container, skip.
|
|
if (!storage.HasItem(enumerable[i].itemValue)) continue;
|
|
|
|
for (var y = 0; y < storage.items.Length; y++)
|
|
{
|
|
var item = storage.items[y];
|
|
if (item.IsEmpty()) continue;
|
|
if (item.itemValue.ItemClass != enumerable[i].itemValue.ItemClass) continue;
|
|
|
|
// If we can completely satisfy the result, let's do that.
|
|
if (item.count >= num)
|
|
{
|
|
item.count -= num;
|
|
// Add the item to the removed items list so we can return it.
|
|
_removedItems.Add(new ItemStack(item.itemValue.Clone(), num));
|
|
num = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, let's just count down until we meet the requirement.
|
|
while (num >= 0)
|
|
{
|
|
item.count--;
|
|
num--;
|
|
if (item.count <= 0)
|
|
{
|
|
_removedItems.Add(new ItemStack(item.itemValue.Clone(), num));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Update the slot on the container, and do the Setmodified(), so that the dedis can get updated.
|
|
if (item.count < 1)
|
|
{
|
|
// Add it to the removed list.
|
|
_removedItems.Add(item.Clone());
|
|
storage.UpdateSlot(y, ItemStack.Empty.Clone());
|
|
|
|
}
|
|
else
|
|
{
|
|
storage.UpdateSlot(y, item);
|
|
}
|
|
}
|
|
storage.SetModified();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
} |