物品容器优化

This commit is contained in:
kercylan98 2023-05-10 12:18:37 +08:00
parent 44745e3f35
commit dd0b486356
9 changed files with 161 additions and 51 deletions

24
game/builtin/item.go Normal file
View File

@ -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
}

View File

@ -3,19 +3,25 @@ package builtin
import ( import (
"github.com/kercylan98/minotaur/game" "github.com/kercylan98/minotaur/game"
"github.com/kercylan98/minotaur/utils/huge" "github.com/kercylan98/minotaur/utils/huge"
"github.com/kercylan98/minotaur/utils/slice"
) )
func NewItemContainer[ItemID comparable, Item game.Item[ItemID]]() *ItemContainer[ItemID, Item] { func NewItemContainer[ItemID comparable, Item game.Item[ItemID]](options ...ItemContainerOption[ItemID, Item]) *ItemContainer[ItemID, Item] {
return &ItemContainer[ItemID, Item]{ itemContainer := &ItemContainer[ItemID, Item]{
items: map[ItemID]map[int64]*itemContainerInfo[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 { type ItemContainer[ItemID comparable, Item game.Item[ItemID]] struct {
sizeLimit int sizeLimit int
size int size int
expandSize 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 { func (slf *ItemContainer[ItemID, Item]) GetSize() int {
@ -30,76 +36,118 @@ func (slf *ItemContainer[ItemID, Item]) GetSizeLimit() int {
return slf.sizeLimit + slf.expandSize 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 { func (slf *ItemContainer[ItemID, Item]) AddItem(item Item, count *huge.Int) error {
if count.LessThanOrEqualTo(huge.IntZero) { if count.LessThanOrEqualTo(huge.IntZero) {
return ErrCannotAddNegativeItem return ErrCannotAddNegativeItem
} }
infos, exist := slf.items[item.GetID()] members, exist := slf.items[item.GetID()]
if !exist { if !exist {
infos = map[int64]*itemContainerInfo[ItemID, Item]{} members = map[int64]*ItemContainerMember[ItemID]{}
slf.items[item.GetID()] = infos slf.items[item.GetID()] = members
} }
info, exist := infos[item.GetGUID()] member, exist := members[item.GetGUID()]
if !exist { if !exist {
if slf.GetSizeLimit() >= slf.GetSize() { if slf.GetSizeLimit() >= slf.GetSize() {
return ErrItemContainerIsFull return ErrItemContainerIsFull
} }
infos[item.GetGUID()] = &itemContainerInfo[ItemID, Item]{ members[item.GetGUID()] = &ItemContainerMember[ItemID]{
item: item, sort: len(slf.sort),
Item: item,
count: count, count: count,
} }
slf.sort = append(slf.sort, &itemContainerSort[ItemID]{
id: item.GetID(),
guid: item.GetGUID(),
})
slf.size++ slf.size++
} else { } else {
info.count = info.count.Add(count) member.count = member.count.Add(count)
} }
return nil return nil
} }
func (slf *ItemContainer[ItemID, Item]) DeductItem(id ItemID, count *huge.Int) error { func (slf *ItemContainer[ItemID, Item]) DeductItem(id ItemID, count *huge.Int) error {
return slf.DeductItemWithGuid(id, -1, count) members, exist := slf.items[id]
} if !exist || len(members) == 0 {
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 return ErrItemNotExist
} }
var backupInfos = make(map[int64]*itemContainerInfo[ItemID, Item]) var backupMembers = make(map[int64]*ItemContainerMember[ItemID])
var pending = count.Copy() var pending = count.Copy()
var deductSize int var deductMembers []*ItemContainerMember[ItemID]
for g, info := range infos { for guid, member := range members {
if g != guid && guid >= 0 { member.bakCount = member.count.Copy()
continue backupMembers[guid] = member
}
info.bakCount = info.count.Copy()
backupInfos[g] = info
if pending.GreaterThanOrEqualTo(info.count) { if pending.GreaterThanOrEqualTo(member.count) {
pending = pending.Sub(info.count) pending = pending.Sub(member.count)
info.count = huge.IntZero member.count = huge.IntZero
} else { } else {
info.count = info.count.Sub(pending) member.count = member.count.Sub(pending)
pending = huge.IntZero pending = huge.IntZero
} }
if info.count.EqualTo(huge.IntZero) { if member.count.EqualTo(huge.IntZero) {
delete(infos, guid) delete(members, guid)
deductSize++ deductMembers = append(deductMembers, member)
} }
if pending.EqualTo(huge.IntZero) { if pending.EqualTo(huge.IntZero) {
break break
} }
} }
if pending.GreaterThan(huge.IntZero) { if pending.GreaterThan(huge.IntZero) {
for g, info := range backupInfos { for guid, member := range backupMembers {
infos[g] = info members[guid] = member
info.count = info.bakCount member.count = member.bakCount
info.bakCount = nil member.bakCount = nil
} }
return ErrItemInsufficientQuantity 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 return nil
} }

View File

@ -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
}

View File

@ -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()
}

View File

@ -2,11 +2,11 @@ package builtin
import "github.com/kercylan98/minotaur/game" 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 通过特定的物品容器非堆叠数量上限创建物品容器 // WithItemContainerSizeLimit 通过特定的物品容器非堆叠数量上限创建物品容器
func WithItemContainerSizeLimit[ItemID comparable, Item game.Item[ItemID]](sizeLimit int) ItemContainerOption[ItemID, Item] { 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 { if sizeLimit <= 0 {
return return
} }

View File

@ -0,0 +1,6 @@
package builtin
type itemContainerSort[ItemID comparable] struct {
id ItemID
guid int64
}

View File

@ -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
}
}

View File

@ -11,6 +11,13 @@ type ItemContainer[ItemID comparable, I Item[ItemID]] interface {
// SetExpandSize 设置拓展非堆叠数量上限 // SetExpandSize 设置拓展非堆叠数量上限
SetExpandSize(size int) 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 添加物品 // AddItem 添加物品
// - 当物品guid相同时如果相同物品id及guid的堆叠数量未达到上限将增加数量否则增加非堆叠数量 // - 当物品guid相同时如果相同物品id及guid的堆叠数量未达到上限将增加数量否则增加非堆叠数量
// - 当物品guid不同时堆叠将不可用每次都将增加非堆叠数量 // - 当物品guid不同时堆叠将不可用每次都将增加非堆叠数量

View File

@ -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
}