diff --git a/game/builtin/item.go b/game/builtin/item.go new file mode 100644 index 0000000..d9b7e3d --- /dev/null +++ b/game/builtin/item.go @@ -0,0 +1,24 @@ +package builtin + +func NewItem[ItemID comparable](id ItemID, options ...ItemOption[ItemID]) *Item[ItemID] { + item := &Item[ItemID]{ + id: id, + } + for _, option := range options { + option(item) + } + return item +} + +type Item[ItemID comparable] struct { + id ItemID + guid int64 +} + +func (slf *Item[ItemID]) GetID() ItemID { + return slf.id +} + +func (slf *Item[ItemID]) GetGUID() int64 { + return slf.guid +} diff --git a/game/builtin/item_container.go b/game/builtin/item_container.go index f6ac85f..fa6b056 100644 --- a/game/builtin/item_container.go +++ b/game/builtin/item_container.go @@ -3,19 +3,25 @@ package builtin import ( "github.com/kercylan98/minotaur/game" "github.com/kercylan98/minotaur/utils/huge" + "github.com/kercylan98/minotaur/utils/slice" ) -func NewItemContainer[ItemID comparable, Item game.Item[ItemID]]() *ItemContainer[ItemID, Item] { - return &ItemContainer[ItemID, Item]{ - items: map[ItemID]map[int64]*itemContainerInfo[ItemID, Item]{}, +func NewItemContainer[ItemID comparable, Item game.Item[ItemID]](options ...ItemContainerOption[ItemID, Item]) *ItemContainer[ItemID, Item] { + itemContainer := &ItemContainer[ItemID, Item]{ + items: map[ItemID]map[int64]*ItemContainerMember[ItemID]{}, } + for _, option := range options { + option(itemContainer) + } + return itemContainer } type ItemContainer[ItemID comparable, Item game.Item[ItemID]] struct { sizeLimit int size int expandSize int - items map[ItemID]map[int64]*itemContainerInfo[ItemID, Item] + items map[ItemID]map[int64]*ItemContainerMember[ItemID] + sort []*itemContainerSort[ItemID] } func (slf *ItemContainer[ItemID, Item]) GetSize() int { @@ -30,76 +36,118 @@ func (slf *ItemContainer[ItemID, Item]) GetSizeLimit() int { return slf.sizeLimit + slf.expandSize } +func (slf *ItemContainer[ItemID, Item]) GetItem(id ItemID) (game.ItemContainerMember[ItemID], error) { + for _, member := range slf.items[id] { + return member, nil + } + return nil, ErrItemNotExist +} + +func (slf *ItemContainer[ItemID, Item]) GetItemWithGuid(id ItemID, guid int64) (game.ItemContainerMember[ItemID], error) { + member, exist := slf.items[id][guid] + if !exist { + return nil, ErrItemNotExist + } + return member, nil +} + +func (slf *ItemContainer[ItemID, Item]) GetItems() []game.ItemContainerMember[ItemID] { + var items []game.ItemContainerMember[ItemID] + for _, sort := range slf.sort { + items = append(items, slf.items[sort.id][sort.guid]) + } + return items +} + 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()] + members, exist := slf.items[item.GetID()] if !exist { - infos = map[int64]*itemContainerInfo[ItemID, Item]{} - slf.items[item.GetID()] = infos + members = map[int64]*ItemContainerMember[ItemID]{} + slf.items[item.GetID()] = members } - info, exist := infos[item.GetGUID()] + member, exist := members[item.GetGUID()] if !exist { if slf.GetSizeLimit() >= slf.GetSize() { return ErrItemContainerIsFull } - infos[item.GetGUID()] = &itemContainerInfo[ItemID, Item]{ - item: item, + members[item.GetGUID()] = &ItemContainerMember[ItemID]{ + sort: len(slf.sort), + Item: item, count: count, } + slf.sort = append(slf.sort, &itemContainerSort[ItemID]{ + id: item.GetID(), + guid: item.GetGUID(), + }) slf.size++ } else { - info.count = info.count.Add(count) + member.count = member.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 { + members, exist := slf.items[id] + if !exist || len(members) == 0 { return ErrItemNotExist } - var backupInfos = make(map[int64]*itemContainerInfo[ItemID, Item]) + var backupMembers = make(map[int64]*ItemContainerMember[ItemID]) 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 + var deductMembers []*ItemContainerMember[ItemID] + for guid, member := range members { + member.bakCount = member.count.Copy() + backupMembers[guid] = member - if pending.GreaterThanOrEqualTo(info.count) { - pending = pending.Sub(info.count) - info.count = huge.IntZero + if pending.GreaterThanOrEqualTo(member.count) { + pending = pending.Sub(member.count) + member.count = huge.IntZero } else { - info.count = info.count.Sub(pending) + member.count = member.count.Sub(pending) pending = huge.IntZero } - if info.count.EqualTo(huge.IntZero) { - delete(infos, guid) - deductSize++ + if member.count.EqualTo(huge.IntZero) { + delete(members, guid) + deductMembers = append(deductMembers, member) } 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 + for guid, member := range backupMembers { + members[guid] = member + member.count = member.bakCount + member.bakCount = nil } return ErrItemInsufficientQuantity } - slf.size -= deductSize + slf.size -= len(deductMembers) + for _, member := range deductMembers { + slice.Del(&slf.sort, member.sort) + } + return nil +} + +func (slf *ItemContainer[ItemID, Item]) DeductItemWithGuid(id ItemID, guid int64, count *huge.Int) error { + member, exist := slf.items[id][guid] + if !exist { + return ErrItemNotExist + } + if count.GreaterThan(member.count) { + return ErrItemInsufficientQuantity + } else { + member.count = member.count.Sub(count) + } + if member.count.EqualTo(huge.IntZero) { + delete(slf.items[id], guid) + slice.Del(&slf.sort, member.sort) + slf.size-- + } return nil } diff --git a/game/builtin/item_container_info.go b/game/builtin/item_container_info.go deleted file mode 100644 index 53d5d33..0000000 --- a/game/builtin/item_container_info.go +++ /dev/null @@ -1,12 +0,0 @@ -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_member.go b/game/builtin/item_container_member.go new file mode 100644 index 0000000..df7d9ab --- /dev/null +++ b/game/builtin/item_container_member.go @@ -0,0 +1,17 @@ +package builtin + +import ( + "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/huge" +) + +type ItemContainerMember[ItemID comparable] struct { + game.Item[ItemID] + sort int + count *huge.Int + bakCount *huge.Int +} + +func (slf *ItemContainerMember[ItemID]) GetCount() *huge.Int { + return slf.count.Copy() +} diff --git a/game/builtin/item_container_options.go b/game/builtin/item_container_options.go index a94fd68..923afc1 100644 --- a/game/builtin/item_container_options.go +++ b/game/builtin/item_container_options.go @@ -2,11 +2,11 @@ package builtin import "github.com/kercylan98/minotaur/game" -type ItemContainerOption[ItemID comparable, Item game.Item[ItemID]] func(container ItemContainer[ItemID, Item]) +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]) { + return func(container *ItemContainer[ItemID, Item]) { if sizeLimit <= 0 { return } diff --git a/game/builtin/item_container_sort.go b/game/builtin/item_container_sort.go new file mode 100644 index 0000000..5ef8414 --- /dev/null +++ b/game/builtin/item_container_sort.go @@ -0,0 +1,6 @@ +package builtin + +type itemContainerSort[ItemID comparable] struct { + id ItemID + guid int64 +} diff --git a/game/builtin/item_options.go b/game/builtin/item_options.go new file mode 100644 index 0000000..1f2e3a9 --- /dev/null +++ b/game/builtin/item_options.go @@ -0,0 +1,10 @@ +package builtin + +type ItemOption[ItemID comparable] func(item *Item[ItemID]) + +// WithItemGuid 通过特定的guid创建物品 +func WithItemGuid[ItemID comparable](guid int64) ItemOption[ItemID] { + return func(item *Item[ItemID]) { + item.guid = guid + } +} diff --git a/game/item_container.go b/game/item_container.go index 8eabe2a..a87c659 100644 --- a/game/item_container.go +++ b/game/item_container.go @@ -11,6 +11,13 @@ type ItemContainer[ItemID comparable, I Item[ItemID]] interface { // SetExpandSize 设置拓展非堆叠数量上限 SetExpandSize(size int) + // GetItem 获取物品 + GetItem(id ItemID) (ItemContainerMember[ItemID], error) + // GetItemWithGuid 根据guid获取物品 + GetItemWithGuid(id ItemID, guid int64) (ItemContainerMember[ItemID], error) + // GetItems 获取所有物品 + GetItems() []ItemContainerMember[ItemID] + // AddItem 添加物品 // - 当物品guid相同时,如果相同物品id及guid的堆叠数量未达到上限,将增加数量,否则增加非堆叠数量 // - 当物品guid不同时,堆叠将不可用,每次都将增加非堆叠数量 diff --git a/game/item_container_member.go b/game/item_container_member.go new file mode 100644 index 0000000..0c512f2 --- /dev/null +++ b/game/item_container_member.go @@ -0,0 +1,10 @@ +package game + +import "github.com/kercylan98/minotaur/utils/huge" + +// ItemContainerMember 物品容器成员信息 +type ItemContainerMember[ItemID comparable] interface { + Item[ItemID] + // GetCount 获取物品数量 + GetCount() *huge.Int +}