209 lines
6.3 KiB
C#

using System.Collections.Generic;
using System.Linq;
namespace ET.Server
{
[FriendOf(typeof(ItemUnit))]
[FriendOf(typeof(BagComponent))]
public static class BagComponentSystem
{
// 约定:>=10000 的道具按装备类处理(独立实例,不堆叠)
private static bool IsEquipItem(int itemId)
{
return itemId >= 10000;
}
public static ItemUnit AddItem(this BagComponent self, int itemId, long count)
{
if (count <= 0)
{
return null;
}
if (!IsEquipItem(itemId))
{
ItemUnit stack = self.ItemMap.Values.Select(x => (ItemUnit)x).FirstOrDefault(x => x.ItemId == itemId && x.HeroId == 0);
if (stack != null)
{
stack.Count += count;
BagNoticeHelper.NotifyItemChange(self.GetParent<Player>(), stack);
if (count > 1000)
{
LogExtensions.Audit("Bag", "LargeResourceAdd", $"{{\"playerId\":{self.GetParent<Player>()?.Id ?? 0},\"itemId\":{itemId},\"count\":{count}}}");
}
return stack;
}
}
long itemIndex = self.NextItemIndex++;
ItemUnit unit = self.AddChildWithId<ItemUnit, long, int, long, long>(itemIndex, itemIndex, itemId, count, 0);
self.ItemMap[itemIndex] = unit;
BagNoticeHelper.NotifyItemChange(self.GetParent<Player>(), unit);
if (count > 1000)
{
LogExtensions.Audit("Bag", "LargeResourceAdd", $"{{\"playerId\":{self.GetParent<Player>()?.Id ?? 0},\"itemId\":{itemId},\"count\":{count}}}");
}
return unit;
}
public static bool RemoveItem(this BagComponent self, int itemId, long count)
{
if (count <= 0)
{
return true;
}
if (self.GetItemCount(itemId) < count)
{
return false;
}
long remain = count;
List<ItemUnit> units = self.ItemMap.Values
.Select(x => (ItemUnit)x)
.Where(x => x.ItemId == itemId && x.HeroId == 0)
.OrderBy(x => x.ItemIndex)
.ToList();
foreach (ItemUnit unit in units)
{
if (remain <= 0)
{
break;
}
long cost = remain > unit.Count ? unit.Count : remain;
unit.Count -= cost;
remain -= cost;
if (unit.Count <= 0)
{
self.RemoveItemByIndex(unit.ItemIndex);
}
else
{
BagNoticeHelper.NotifyItemChange(self.GetParent<Player>(), unit);
}
}
return remain == 0;
}
public static bool RemoveItemByIndex(this BagComponent self, long itemIndex)
{
if (!self.ItemMap.TryGetValue(itemIndex, out EntityRef<ItemUnit> unitRef))
{
return false;
}
ItemUnit unit = unitRef;
self.ItemMap.Remove(itemIndex);
BagNoticeHelper.NotifyItemRemove(self.GetParent<Player>(), itemIndex);
unit.Dispose();
return true;
}
public static bool SetHeroIdOnEquip(this BagComponent self, long itemIndex, long heroId)
{
if (!self.ItemMap.TryGetValue(itemIndex, out EntityRef<ItemUnit> unitRef))
{
return false;
}
ItemUnit unit = unitRef;
unit.HeroId = heroId;
BagNoticeHelper.NotifyItemChange(self.GetParent<Player>(), unit);
return true;
}
public static void AddItems(this BagComponent self, List<RewardEntry> rewards)
{
if (rewards == null)
{
return;
}
foreach (RewardEntry reward in rewards)
{
self.AddItem(reward.ItemId, reward.Count);
}
self.GetParent<Player>()?.SetDirty();
}
public static bool RemoveItems(this BagComponent self, List<CostEntry> costs)
{
if (!self.HasItems(costs))
{
return false;
}
foreach (CostEntry cost in costs)
{
if (!self.RemoveItem(cost.ItemId, cost.Count))
{
return false;
}
}
self.GetParent<Player>()?.SetDirty();
return true;
}
public static long GetItemCount(this BagComponent self, int itemId)
{
long total = 0;
foreach (EntityRef<ItemUnit> unitRef in self.ItemMap.Values)
{
ItemUnit unit = unitRef;
if (unit.ItemId == itemId && unit.HeroId == 0)
{
total += unit.Count;
}
}
return total;
}
public static bool HasItems(this BagComponent self, List<CostEntry> costs)
{
if (costs == null)
{
return true;
}
foreach (CostEntry cost in costs)
{
if (self.GetItemCount(cost.ItemId) < cost.Count)
{
return false;
}
}
return true;
}
public static List<ItemUnit> GetAllItems(this BagComponent self)
{
return self.ItemMap.Values.Select(x => (ItemUnit)x).OrderBy(x => x.ItemIndex).ToList();
}
public static void ClearBagKeepEquipped(this BagComponent self)
{
List<long> removed = new();
foreach (EntityRef<ItemUnit> unitRef in self.ItemMap.Values)
{
ItemUnit item = unitRef;
if (item.HeroId == 0)
{
removed.Add(item.ItemIndex);
}
}
foreach (long itemIndex in removed)
{
self.RemoveItemByIndex(itemIndex);
}
self.GetParent<Player>()?.SetDirty();
}
}
}