|
@@ -9,19 +9,15 @@ import (
|
|
|
usercenter "server/datacenter"
|
|
|
maildb "server/datacenter/mail_db"
|
|
|
mysqlmgr "server/db/mysql"
|
|
|
+ "server/msg"
|
|
|
+ "strings"
|
|
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
|
)
|
|
|
|
|
|
-// Item 背包中的道具
|
|
|
-type Item struct {
|
|
|
- ID int `json:"item_id"`
|
|
|
- Quantity int `json:"quantity"`
|
|
|
-}
|
|
|
-
|
|
|
// InventoryData 背包数据结构
|
|
|
type InventoryData struct {
|
|
|
- Slots []Item `json:"slots"`
|
|
|
+ Slots []msg.ItemRequest `json:"slots"`
|
|
|
}
|
|
|
|
|
|
// ItemInfo 道具基础信息
|
|
@@ -31,19 +27,13 @@ type ItemInfo struct {
|
|
|
MaxStack int `json:"max_stack"` // 0表示不可叠加
|
|
|
}
|
|
|
|
|
|
-// ItemRequest 添加道具请求
|
|
|
-type ItemRequest struct {
|
|
|
- ItemID int `json:"item_id"`
|
|
|
- Quantity int `json:"quantity"`
|
|
|
-}
|
|
|
-
|
|
|
// GetUserInventory 获取用户背包
|
|
|
func GetUserInventory(userID string) (*InventoryData, error) {
|
|
|
var dataStr string
|
|
|
err := mysqlmgr.QueryRow("SELECT inventory_data FROM user_inventory WHERE user_id = ?", userID).Scan(&dataStr)
|
|
|
if err != nil {
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
- return &InventoryData{Slots: make([]Item, 0)}, nil
|
|
|
+ return &InventoryData{Slots: make([]msg.ItemRequest, 0)}, nil
|
|
|
}
|
|
|
return nil, fmt.Errorf("查询用户背包失败: %v", err)
|
|
|
}
|
|
@@ -78,7 +68,7 @@ func SaveUserInventory(userID string, data *InventoryData) error {
|
|
|
}
|
|
|
|
|
|
// GetItemInfo 获取道具信息 ,::后面改成从 redis 查询 ,实现逻辑是 启动服务器时,把所有道具添加到redis库里
|
|
|
-func GetItemInfo(itemID int) (*ItemInfo, error) {
|
|
|
+func GetItemInfo(itemID int32) (*ItemInfo, error) {
|
|
|
var item ItemInfo
|
|
|
err := mysqlmgr.QueryRow(`
|
|
|
SELECT item_id, item_name, max_stack
|
|
@@ -92,7 +82,7 @@ func GetItemInfo(itemID int) (*ItemInfo, error) {
|
|
|
}
|
|
|
|
|
|
// AddItemsToMail 添加道具到邮箱
|
|
|
-func AddItemsToMail(userID string, items []ItemRequest) error {
|
|
|
+func AddItemsToMail(userID string, items []msg.ItemRequest) error {
|
|
|
// 开始事务
|
|
|
tx, err := mysqlmgr.Begin()
|
|
|
if err != nil {
|
|
@@ -138,7 +128,7 @@ func AddItemsToMail(userID string, items []ItemRequest) error {
|
|
|
}
|
|
|
|
|
|
// AcquireMultipleItems 获取多个道具
|
|
|
-func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequest, error) {
|
|
|
+func AcquireMultipleItems(userID string, itemRequests []msg.ItemRequest) ([]msg.ItemRequest, error) {
|
|
|
// 1. 获取用户最大格子数
|
|
|
var maxSlots int
|
|
|
err := mysqlmgr.QueryRow("SELECT max_slots FROM users WHERE user_id = ?", userID).Scan(&maxSlots)
|
|
@@ -159,8 +149,8 @@ func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequ
|
|
|
}
|
|
|
|
|
|
// 4. 处理每种道具
|
|
|
- var mailItems []ItemRequest
|
|
|
- updatedInventory := &InventoryData{Slots: make([]Item, len(inventory.Slots))}
|
|
|
+ var mailItems []msg.ItemRequest
|
|
|
+ updatedInventory := &InventoryData{Slots: make([]msg.ItemRequest, len(inventory.Slots))}
|
|
|
copy(updatedInventory.Slots, inventory.Slots)
|
|
|
|
|
|
for _, req := range itemRequests {
|
|
@@ -175,10 +165,10 @@ func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequ
|
|
|
if itemInfo.MaxStack > 1 {
|
|
|
// 先尝试堆叠到已有格子
|
|
|
for i := range updatedInventory.Slots {
|
|
|
- if updatedInventory.Slots[i].ID == req.ItemID &&
|
|
|
- updatedInventory.Slots[i].Quantity < itemInfo.MaxStack {
|
|
|
- canAdd := itemInfo.MaxStack - updatedInventory.Slots[i].Quantity
|
|
|
- add := min(remainingQuantity, canAdd)
|
|
|
+ if updatedInventory.Slots[i].ItemID == req.ItemID &&
|
|
|
+ updatedInventory.Slots[i].Quantity < int32(itemInfo.MaxStack) {
|
|
|
+ canAdd := itemInfo.MaxStack - int(updatedInventory.Slots[i].Quantity)
|
|
|
+ add := min(remainingQuantity, int32(canAdd))
|
|
|
updatedInventory.Slots[i].Quantity += add
|
|
|
remainingQuantity -= add
|
|
|
if remainingQuantity == 0 {
|
|
@@ -192,7 +182,7 @@ func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequ
|
|
|
for remainingQuantity > 0 {
|
|
|
if remainingSlots <= 0 {
|
|
|
// 没有空格子了,剩余道具发到邮箱
|
|
|
- mailItems = append(mailItems, ItemRequest{
|
|
|
+ mailItems = append(mailItems, msg.ItemRequest{
|
|
|
ItemID: req.ItemID,
|
|
|
Quantity: remainingQuantity,
|
|
|
})
|
|
@@ -203,17 +193,17 @@ func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequ
|
|
|
// 不可叠加道具或可叠加道具的新格子
|
|
|
if itemInfo.MaxStack <= 1 {
|
|
|
// 不可叠加道具,每个占一个格子
|
|
|
- updatedInventory.Slots = append(updatedInventory.Slots, Item{
|
|
|
- ID: req.ItemID,
|
|
|
+ updatedInventory.Slots = append(updatedInventory.Slots, msg.ItemRequest{
|
|
|
+ ItemID: req.ItemID,
|
|
|
Quantity: 1,
|
|
|
})
|
|
|
remainingQuantity--
|
|
|
remainingSlots--
|
|
|
} else {
|
|
|
// 可叠加道具,创建新格子
|
|
|
- add := min(remainingQuantity, itemInfo.MaxStack)
|
|
|
- updatedInventory.Slots = append(updatedInventory.Slots, Item{
|
|
|
- ID: req.ItemID,
|
|
|
+ add := min(remainingQuantity, int32(itemInfo.MaxStack))
|
|
|
+ updatedInventory.Slots = append(updatedInventory.Slots, msg.ItemRequest{
|
|
|
+ ItemID: req.ItemID,
|
|
|
Quantity: add,
|
|
|
})
|
|
|
remainingQuantity -= add
|
|
@@ -241,7 +231,7 @@ func AcquireMultipleItems(userID string, itemRequests []ItemRequest) ([]ItemRequ
|
|
|
}
|
|
|
|
|
|
// ConsumeMultipleItems 消耗多个道具
|
|
|
-func ConsumeMultipleItems(userID string, itemRequests []ItemRequest) error {
|
|
|
+func ConsumeMultipleItems(userID string, itemRequests []msg.ItemRequest) error {
|
|
|
// 1. 获取当前背包数据
|
|
|
inventory, err := GetUserInventory(userID)
|
|
|
if err != nil {
|
|
@@ -249,15 +239,15 @@ func ConsumeMultipleItems(userID string, itemRequests []ItemRequest) error {
|
|
|
}
|
|
|
|
|
|
// 2. 检查道具数量是否足够
|
|
|
- itemCounts := make(map[int]int)
|
|
|
+ itemCounts := make(map[int32]int32)
|
|
|
for _, req := range itemRequests {
|
|
|
itemCounts[req.ItemID] += req.Quantity
|
|
|
}
|
|
|
|
|
|
// 统计当前拥有的道具数量
|
|
|
- currentCounts := make(map[int]int)
|
|
|
+ currentCounts := make(map[int32]int32)
|
|
|
for _, slot := range inventory.Slots {
|
|
|
- currentCounts[slot.ID] += slot.Quantity
|
|
|
+ currentCounts[slot.ItemID] += slot.Quantity
|
|
|
}
|
|
|
|
|
|
// 检查是否足够
|
|
@@ -270,24 +260,24 @@ func ConsumeMultipleItems(userID string, itemRequests []ItemRequest) error {
|
|
|
}
|
|
|
|
|
|
// 3. 扣除道具
|
|
|
- newSlots := make([]Item, 0, len(inventory.Slots))
|
|
|
- remainingToConsume := make(map[int]int)
|
|
|
+ newSlots := make([]msg.ItemRequest, 0, len(inventory.Slots))
|
|
|
+ remainingToConsume := make(map[int32]int32)
|
|
|
for itemID, count := range itemCounts {
|
|
|
remainingToConsume[itemID] = count
|
|
|
}
|
|
|
|
|
|
for _, slot := range inventory.Slots {
|
|
|
- if consume, ok := remainingToConsume[slot.ID]; ok && consume > 0 {
|
|
|
+ if consume, ok := remainingToConsume[slot.ItemID]; ok && consume > 0 {
|
|
|
if slot.Quantity > consume {
|
|
|
// 这个格子有剩余
|
|
|
- newSlots = append(newSlots, Item{
|
|
|
- ID: slot.ID,
|
|
|
+ newSlots = append(newSlots, msg.ItemRequest{
|
|
|
+ ItemID: slot.ItemID,
|
|
|
Quantity: slot.Quantity - consume,
|
|
|
})
|
|
|
- remainingToConsume[slot.ID] = 0
|
|
|
+ remainingToConsume[slot.ItemID] = 0
|
|
|
} else {
|
|
|
// 完全消耗这个格子的道具
|
|
|
- remainingToConsume[slot.ID] -= slot.Quantity
|
|
|
+ remainingToConsume[slot.ItemID] -= slot.Quantity
|
|
|
}
|
|
|
} else {
|
|
|
// 不需要消耗这个格子的道具
|
|
@@ -300,18 +290,109 @@ func ConsumeMultipleItems(userID string, itemRequests []ItemRequest) error {
|
|
|
return SaveUserInventory(userID, updatedInventory)
|
|
|
}
|
|
|
|
|
|
-func min(a, b int) int {
|
|
|
+func min(a, b int32) int32 {
|
|
|
if a < b {
|
|
|
return a
|
|
|
}
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
+// InventoryItem 背包物品详情
|
|
|
+type InventoryItem struct {
|
|
|
+ ItemID int `json:"item_id"`
|
|
|
+ ItemName string `json:"item_name"`
|
|
|
+ ItemType int `json:"item_type"`
|
|
|
+ Quantity int `json:"quantity"`
|
|
|
+ MaxStack int `json:"max_stack"`
|
|
|
+}
|
|
|
+
|
|
|
+// GetInventoryItemsByType 根据道具类型获取背包物品列表
|
|
|
+func GetInventoryItemsByType(userID string, itemType int) ([]InventoryItem, error) {
|
|
|
+ // 1. 获取用户背包数据
|
|
|
+ inventory, err := GetUserInventory(userID)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 如果没有道具,直接返回空列表
|
|
|
+ if len(inventory.Slots) == 0 {
|
|
|
+ return []InventoryItem{}, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 收集所有需要查询的道具ID
|
|
|
+ itemIDs := make([]int32, 0, len(inventory.Slots))
|
|
|
+ slotMap := make(map[int32][]msg.ItemRequest) // itemID -> []Item(同种道具的所有格子)
|
|
|
+ for _, slot := range inventory.Slots {
|
|
|
+ itemIDs = append(itemIDs, slot.ItemID)
|
|
|
+ slotMap[slot.ItemID] = append(slotMap[slot.ItemID], slot)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 查询这些道具的基础信息 , 后面修成成从 redis 获取
|
|
|
+ query := `
|
|
|
+ SELECT item_id, item_name, item_type, max_stack
|
|
|
+ FROM items
|
|
|
+ WHERE item_id IN (` + placeholders(len(itemIDs)) + `)
|
|
|
+ AND item_type = ?
|
|
|
+ `
|
|
|
+
|
|
|
+ // 将itemIDs转换为interface{}切片用于Query
|
|
|
+ args := make([]interface{}, 0, len(itemIDs)+1)
|
|
|
+ for _, id := range itemIDs {
|
|
|
+ args = append(args, id)
|
|
|
+ }
|
|
|
+ args = append(args, itemType)
|
|
|
+
|
|
|
+ rows, err := mysqlmgr.Query(query, args...)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("查询道具信息失败: %v", err)
|
|
|
+ }
|
|
|
+ defer rows.Close()
|
|
|
+
|
|
|
+ // 5. 构建返回结果
|
|
|
+ var result []InventoryItem
|
|
|
+ for rows.Next() {
|
|
|
+ var itemInfo struct {
|
|
|
+ ID int
|
|
|
+ Name string
|
|
|
+ Type int
|
|
|
+ MaxStack int
|
|
|
+ }
|
|
|
+ err := rows.Scan(&itemInfo.ID, &itemInfo.Name, &itemInfo.Type, &itemInfo.MaxStack)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("解析道具信息失败: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取该道具在背包中的所有格子
|
|
|
+ if slots, ok := slotMap[int32(itemInfo.ID)]; ok {
|
|
|
+ for _, slot := range slots {
|
|
|
+ result = append(result, InventoryItem{
|
|
|
+ ItemID: itemInfo.ID,
|
|
|
+ ItemName: itemInfo.Name,
|
|
|
+ ItemType: itemInfo.Type,
|
|
|
+ Quantity: int(slot.Quantity),
|
|
|
+ MaxStack: itemInfo.MaxStack,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+// placeholders 生成SQL占位符字符串
|
|
|
+func placeholders(n int) string {
|
|
|
+ phs := make([]string, n)
|
|
|
+ for i := range phs {
|
|
|
+ phs[i] = "?"
|
|
|
+ }
|
|
|
+ return strings.Join(phs, ",")
|
|
|
+}
|
|
|
+
|
|
|
func example() {
|
|
|
|
|
|
// 示例1: 同时获取多种道具
|
|
|
userID := "user123"
|
|
|
- itemsToAdd := []ItemRequest{
|
|
|
+ itemsToAdd := []msg.ItemRequest{
|
|
|
{ItemID: 101, Quantity: 15}, // 可叠加道具
|
|
|
{ItemID: 201, Quantity: 3}, // 不可叠加道具
|
|
|
{ItemID: 301, Quantity: 5}, // 其他道具
|
|
@@ -327,7 +408,7 @@ func example() {
|
|
|
}
|
|
|
|
|
|
// 示例2: 同时消耗多种道具
|
|
|
- itemsToConsume := []ItemRequest{
|
|
|
+ itemsToConsume := []msg.ItemRequest{
|
|
|
{ItemID: 101, Quantity: 5},
|
|
|
{ItemID: 201, Quantity: 1},
|
|
|
}
|