xy há 1 dia atrás
pai
commit
f990dc9f4a
4 ficheiros alterados com 291 adições e 44 exclusões
  1. 8 1
      bin/client_msg/bag.proto
  2. 124 43
      src/server/datacenter/bag_db/bag.go
  3. 132 0
      src/server/msg/bag.pb.go
  4. 27 0
      xyzw.pem

+ 8 - 1
bin/client_msg/bag.proto

@@ -2,4 +2,11 @@ syntax = "proto3";
 
 option go_package = "./msg";
 
-import "common.proto";          // 直接引入
+import "common.proto";          // 直接引入
+
+
+message ItemRequest {
+    int32 ItemID = 1;
+    int32 Quantity = 2; 
+}
+

+ 124 - 43
src/server/datacenter/bag_db/bag.go

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

+ 132 - 0
src/server/msg/bag.pb.go

@@ -0,0 +1,132 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.6
+// 	protoc        v3.21.5
+// source: bag.proto
+
+package msg
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ItemRequest struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	ItemID        int32                  `protobuf:"varint,1,opt,name=ItemID,proto3" json:"ItemID,omitempty"`
+	Quantity      int32                  `protobuf:"varint,2,opt,name=Quantity,proto3" json:"Quantity,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ItemRequest) Reset() {
+	*x = ItemRequest{}
+	mi := &file_bag_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ItemRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ItemRequest) ProtoMessage() {}
+
+func (x *ItemRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_bag_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ItemRequest.ProtoReflect.Descriptor instead.
+func (*ItemRequest) Descriptor() ([]byte, []int) {
+	return file_bag_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ItemRequest) GetItemID() int32 {
+	if x != nil {
+		return x.ItemID
+	}
+	return 0
+}
+
+func (x *ItemRequest) GetQuantity() int32 {
+	if x != nil {
+		return x.Quantity
+	}
+	return 0
+}
+
+var File_bag_proto protoreflect.FileDescriptor
+
+const file_bag_proto_rawDesc = "" +
+	"\n" +
+	"\tbag.proto\x1a\fcommon.proto\"A\n" +
+	"\vItemRequest\x12\x16\n" +
+	"\x06ItemID\x18\x01 \x01(\x05R\x06ItemID\x12\x1a\n" +
+	"\bQuantity\x18\x02 \x01(\x05R\bQuantityB\aZ\x05./msgb\x06proto3"
+
+var (
+	file_bag_proto_rawDescOnce sync.Once
+	file_bag_proto_rawDescData []byte
+)
+
+func file_bag_proto_rawDescGZIP() []byte {
+	file_bag_proto_rawDescOnce.Do(func() {
+		file_bag_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_bag_proto_rawDesc), len(file_bag_proto_rawDesc)))
+	})
+	return file_bag_proto_rawDescData
+}
+
+var file_bag_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_bag_proto_goTypes = []any{
+	(*ItemRequest)(nil), // 0: ItemRequest
+}
+var file_bag_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_bag_proto_init() }
+func file_bag_proto_init() {
+	if File_bag_proto != nil {
+		return
+	}
+	file_common_proto_init()
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_bag_proto_rawDesc), len(file_bag_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_bag_proto_goTypes,
+		DependencyIndexes: file_bag_proto_depIdxs,
+		MessageInfos:      file_bag_proto_msgTypes,
+	}.Build()
+	File_bag_proto = out.File
+	file_bag_proto_goTypes = nil
+	file_bag_proto_depIdxs = nil
+}

+ 27 - 0
xyzw.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAlPWQzqe8ODuapN+9E29R43H1mW3/KoUQEOAUUd9RG4l1Ib8Q
+f+fXCorHo73xa5YfV4v6D9ArsaIEZzbJvEI4P1rjG7OMzmMqd01LM5XhNLoIyS6p
+x1NBF3Gh2DJkzdzsaISN5lqoLt6qjjIjSb+II7S5k7FUI9DBg3K55An+gqcEJHJs
+kEhZbBkAzFriSGaAMTdZMEFu2oUQF7ynU0/imKKXFjPWWKIuazK6731iLN38QAWX
+k+h9NGBjFe0endnWNBdyUfS6aA+EFqWTgOVKUj5FRownf7c0mKhZNHC+CSDrFiDv
+kYBR20/mJwD7z5iLpYySgmaXg2UDX6H4XRunjQIDAQABAoIBAQCHwYXH0XboiOnX
+eVGIdNvcve9ndagnyD1sI8xhEXWJ8yydJNSUvWZuZSytPl7X/mlyEFBGOSKZMV9x
+8azJtlAs7Vgt1uVs81OwhvESgnZM5386WxzAXE/mXdlyf/r+42lRl/z7A4Rjsusd
+zPP8MmKQqBS5VdOpEIhMlDJ2ceVSjBxPCsjBq/kBN6vbIYW6JfBItb9m/Q0w0EbL
+v/Rv1lrDzt7cqeEQ4Q4pnEM6a7ozYgNKAPgbbugh4Nb0o6JoGbzwpBwVYEGObgOn
+BGiPnur1DSo66xDn0vqdTDYxOq75/KaaoReuJe/mm8SNelhHERNM5FY+5ULF3Mau
+zOSC9XgBAoGBAOODmQFK0nRO8NiBL9LN3m9xA4/0E7b4hefVeyL6fbCPOqh/lplT
+Rak7wBW6soIOMARmJD53ecj8OI8tVlZFbpqKbr9L1s2BZn+S/rDqK+JCBS8J7MVv
+3K7dcguoPUGZUp5bdctlAlOiyp/uNPanyInzRjqTv6NL12F9pv5T9lTtAoGBAKec
+FkhP3TIR6EFzF3GQJuo3S69TpbYKVMcrhx9VRwGT0qCQ9BE47DG/09VRqwkiDlwP
+Wj3DmC2ZJ4P+AiUUnLl1QuAtBBxLMl6ahbIEwlhGBYUGAxza05XqFwQ/zU39XmDt
+qEBLOaEtBKTALHvtAGDA6uqJhQA9LbUI6sc4a+khAoGAToXN2gdT6XaRY3f65HvP
+KJFN1HI+F6lgteoVTLY9iSF18k/Oz25RHZ6UpitAjuiMpAgIvFKKAtciQjA4mx/t
+k4LxxC5NnbHqiV9XbgH0UWvN1DVNtbrs5KFjSiivs6NSQ3t3hVKAYhNOcbJKL1Mr
+QIlpFLCHtLlpRamTaDXcT+UCgYAqkmS+fTqLqyy44wjDWX/o4Z6hq7ddY4ZhCFdL
+yBc++VL4YZj8ft7PTA/8EMBGk5XeIDAlm/adLldxGSVmUbP1DymrUwPGQ/tJOCpZ
+KwhJ748bWImV3Kb9XvX1qFb3RjGgoPypR/IdVBfn2L/zwiDkclu4srFLfD6NyvQH
+IfeWwQKBgDqLbRg2uKE6IzLo7FbPWXEXR1xh1TojgY22rrcr9tGYqXzYpV+D/DgS
+wSI6xBTMXHEVp+DgB4wVnZ25uCI1WfBpXj+T3MQp7v1Iccutc+SjtVmEVWcby3c4
+6oyxSJa9fSBjvFLmRjpwWt60RMgDCWmLr2xDxb9KNNdZiYpYHT41
+-----END RSA PRIVATE KEY-----