物品容器优化
This commit is contained in:
parent
44745e3f35
commit
dd0b486356
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package builtin
|
||||
|
||||
type itemContainerSort[ItemID comparable] struct {
|
||||
id ItemID
|
||||
guid int64
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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不同时,堆叠将不可用,每次都将增加非堆叠数量
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue