From 32f3083e87bd02812632201c1ab40c05fcda689a Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Wed, 10 May 2023 11:33:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=A9=E5=93=81=E5=AE=B9=E5=99=A8=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/builtin/item_container.go | 105 +++++++++++++++++++++++++ game/builtin/item_container_errors.go | 10 +++ game/builtin/item_container_info.go | 12 +++ game/builtin/item_container_options.go | 15 ++++ game/item.go | 10 +++ game/item_container.go | 24 ++++++ 6 files changed, 176 insertions(+) create mode 100644 game/builtin/item_container.go create mode 100644 game/builtin/item_container_errors.go create mode 100644 game/builtin/item_container_info.go create mode 100644 game/builtin/item_container_options.go create mode 100644 game/item.go create mode 100644 game/item_container.go diff --git a/game/builtin/item_container.go b/game/builtin/item_container.go new file mode 100644 index 0000000..f6ac85f --- /dev/null +++ b/game/builtin/item_container.go @@ -0,0 +1,105 @@ +package builtin + +import ( + "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/huge" +) + +func NewItemContainer[ItemID comparable, Item game.Item[ItemID]]() *ItemContainer[ItemID, Item] { + return &ItemContainer[ItemID, Item]{ + items: map[ItemID]map[int64]*itemContainerInfo[ItemID, Item]{}, + } +} + +type ItemContainer[ItemID comparable, Item game.Item[ItemID]] struct { + sizeLimit int + size int + expandSize int + items map[ItemID]map[int64]*itemContainerInfo[ItemID, Item] +} + +func (slf *ItemContainer[ItemID, Item]) GetSize() int { + return slf.size +} + +func (slf *ItemContainer[ItemID, Item]) SetExpandSize(size int) { + slf.expandSize = size +} + +func (slf *ItemContainer[ItemID, Item]) GetSizeLimit() int { + return slf.sizeLimit + slf.expandSize +} + +func (slf *ItemContainer[ItemID, Item]) AddItem(item Item, count *huge.Int) error { + if count.LessThanOrEqualTo(huge.IntZero) { + return ErrCannotAddNegativeItem + } + infos, exist := slf.items[item.GetID()] + if !exist { + infos = map[int64]*itemContainerInfo[ItemID, Item]{} + slf.items[item.GetID()] = infos + + } + info, exist := infos[item.GetGUID()] + if !exist { + if slf.GetSizeLimit() >= slf.GetSize() { + return ErrItemContainerIsFull + } + infos[item.GetGUID()] = &itemContainerInfo[ItemID, Item]{ + item: item, + count: count, + } + slf.size++ + } else { + info.count = info.count.Add(count) + } + return nil +} + +func (slf *ItemContainer[ItemID, Item]) DeductItem(id ItemID, count *huge.Int) error { + return slf.DeductItemWithGuid(id, -1, count) +} + +func (slf *ItemContainer[ItemID, Item]) DeductItemWithGuid(id ItemID, guid int64, count *huge.Int) error { + infos, exist := slf.items[id] + if !exist || len(infos) == 0 { + return ErrItemNotExist + } + + var backupInfos = make(map[int64]*itemContainerInfo[ItemID, Item]) + var pending = count.Copy() + var deductSize int + for g, info := range infos { + if g != guid && guid >= 0 { + continue + } + info.bakCount = info.count.Copy() + backupInfos[g] = info + + if pending.GreaterThanOrEqualTo(info.count) { + pending = pending.Sub(info.count) + info.count = huge.IntZero + } else { + info.count = info.count.Sub(pending) + pending = huge.IntZero + } + + if info.count.EqualTo(huge.IntZero) { + delete(infos, guid) + deductSize++ + } + if pending.EqualTo(huge.IntZero) { + break + } + } + if pending.GreaterThan(huge.IntZero) { + for g, info := range backupInfos { + infos[g] = info + info.count = info.bakCount + info.bakCount = nil + } + return ErrItemInsufficientQuantity + } + slf.size -= deductSize + return nil +} diff --git a/game/builtin/item_container_errors.go b/game/builtin/item_container_errors.go new file mode 100644 index 0000000..2201203 --- /dev/null +++ b/game/builtin/item_container_errors.go @@ -0,0 +1,10 @@ +package builtin + +import "errors" + +var ( + ErrCannotAddNegativeItem = errors.New("cannot add items with negative quantities") + ErrItemNotExist = errors.New("item not exist") + ErrItemInsufficientQuantity = errors.New("item insufficient quantity") + ErrItemContainerIsFull = errors.New("item container is full") +) diff --git a/game/builtin/item_container_info.go b/game/builtin/item_container_info.go new file mode 100644 index 0000000..53d5d33 --- /dev/null +++ b/game/builtin/item_container_info.go @@ -0,0 +1,12 @@ +package builtin + +import ( + "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/huge" +) + +type itemContainerInfo[ItemID comparable, Item game.Item[ItemID]] struct { + item Item + count *huge.Int + bakCount *huge.Int +} diff --git a/game/builtin/item_container_options.go b/game/builtin/item_container_options.go new file mode 100644 index 0000000..a94fd68 --- /dev/null +++ b/game/builtin/item_container_options.go @@ -0,0 +1,15 @@ +package builtin + +import "github.com/kercylan98/minotaur/game" + +type ItemContainerOption[ItemID comparable, Item game.Item[ItemID]] func(container ItemContainer[ItemID, Item]) + +// WithItemContainerSizeLimit 通过特定的物品容器非堆叠数量上限创建物品容器 +func WithItemContainerSizeLimit[ItemID comparable, Item game.Item[ItemID]](sizeLimit int) ItemContainerOption[ItemID, Item] { + return func(container ItemContainer[ItemID, Item]) { + if sizeLimit <= 0 { + return + } + container.sizeLimit = sizeLimit + } +} diff --git a/game/item.go b/game/item.go new file mode 100644 index 0000000..be78ba6 --- /dev/null +++ b/game/item.go @@ -0,0 +1,10 @@ +package game + +type Item[ID comparable] interface { + // GetID 获取物品ID + GetID() ID + // GetGUID 获取物品GUID + // - 用于标识同一件物品不同的特征 + // - 负数的GUID在内置功能中可能会被用于特殊判定,如果需要负数建议另外对特殊功能进行实现 + GetGUID() int64 +} diff --git a/game/item_container.go b/game/item_container.go new file mode 100644 index 0000000..8eabe2a --- /dev/null +++ b/game/item_container.go @@ -0,0 +1,24 @@ +package game + +import "github.com/kercylan98/minotaur/utils/huge" + +// ItemContainer 物品容器 +type ItemContainer[ItemID comparable, I Item[ItemID]] interface { + // GetSize 获取容器物品非堆叠数量 + GetSize() int + // GetSizeLimit 获取容器物品非堆叠数量上限 + GetSizeLimit() int + // SetExpandSize 设置拓展非堆叠数量上限 + SetExpandSize(size int) + + // AddItem 添加物品 + // - 当物品guid相同时,如果相同物品id及guid的堆叠数量未达到上限,将增加数量,否则增加非堆叠数量 + // - 当物品guid不同时,堆叠将不可用,每次都将增加非堆叠数量 + AddItem(item I, count *huge.Int) error + // DeductItem 扣除特定物品数量,当数量为0将被移除,数量不足时将不进行任何改变 + // - 将查找特定id的物品,无论guid是否相同,都有可能被扣除直到达到扣除数量 + // - 当count为负数时,由于负负得正,无论guid是否相同,都有可能被增加物品数量直到达到扣除数量 + DeductItem(id ItemID, count *huge.Int) error + // DeductItemWithGuid 更为精准的扣除特定物品数量,可参考 DeductItem + DeductItemWithGuid(id ItemID, guid int64, count *huge.Int) error +}