物品容器优化
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 (
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 设置拓展非堆叠数量上限
|
||||||
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不同时,堆叠将不可用,每次都将增加非堆叠数量
|
||||||
|
|
|
||||||
|
|
@ -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