mirror of Walter-Sparrow / lunar-tear
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add consumable item sell functionality

+128 -11
+1 -1
server/Makefile
··· 1 1 # Proto generation: outputs to gen/proto/ (module=lunar-tear/server). 2 2 # All proto files have go_package. Only protos used by the server are generated here 3 3 # (generating all would put them in one package and cause name clashes). 4 - PROTO_USED = proto/banner.proto proto/battle.proto proto/bighunt.proto proto/cageornament.proto proto/character.proto proto/characterboard.proto proto/characterviewer.proto proto/companion.proto proto/config.proto proto/contentsstory.proto proto/costume.proto proto/data.proto proto/deck.proto proto/dokan.proto proto/explore.proto proto/friend.proto proto/gacha.proto proto/gameplay.proto proto/gift.proto proto/gimmick.proto proto/labyrinth.proto proto/loginbonus.proto proto/material.proto proto/mission.proto proto/movie.proto proto/navicutin.proto proto/omikuji.proto proto/notification.proto proto/parts.proto proto/portalcage.proto proto/pvp.proto proto/quest.proto proto/reward.proto proto/shop.proto proto/sidestoryquest.proto proto/tutorial.proto proto/user.proto proto/weapon.proto 4 + PROTO_USED = proto/banner.proto proto/battle.proto proto/bighunt.proto proto/cageornament.proto proto/character.proto proto/characterboard.proto proto/characterviewer.proto proto/companion.proto proto/config.proto proto/consumableitem.proto proto/contentsstory.proto proto/costume.proto proto/data.proto proto/deck.proto proto/dokan.proto proto/explore.proto proto/friend.proto proto/gacha.proto proto/gameplay.proto proto/gift.proto proto/gimmick.proto proto/labyrinth.proto proto/loginbonus.proto proto/material.proto proto/mission.proto proto/movie.proto proto/navicutin.proto proto/omikuji.proto proto/notification.proto proto/parts.proto proto/portalcage.proto proto/pvp.proto proto/quest.proto proto/reward.proto proto/shop.proto proto/sidestoryquest.proto proto/tutorial.proto proto/user.proto proto/weapon.proto 5 5 6 6 proto: 7 7 protoc -I . $(PROTO_USED) --go_out=. --go_opt=module=lunar-tear/server --go-grpc_out=. --go-grpc_opt=module=lunar-tear/server
+4
server/cmd/lunar-tear/grpc.go
··· 55 55 characterRebirthCatalog *masterdata.CharacterRebirthCatalog, 56 56 companionCatalog *masterdata.CompanionCatalog, 57 57 materialCatalog *masterdata.MaterialCatalog, 58 + consumableItemCatalog *masterdata.ConsumableItemCatalog, 58 59 gameConfig *masterdata.GameConfig, 59 60 sideStoryCatalog *masterdata.SideStoryCatalog, 60 61 bigHuntCatalog *masterdata.BigHuntCatalog, ··· 90 91 characterRebirthCatalog, 91 92 companionCatalog, 92 93 materialCatalog, 94 + consumableItemCatalog, 93 95 gameConfig, 94 96 sideStoryCatalog, 95 97 bigHuntCatalog, ··· 126 128 characterRebirthCatalog *masterdata.CharacterRebirthCatalog, 127 129 companionCatalog *masterdata.CompanionCatalog, 128 130 materialCatalog *masterdata.MaterialCatalog, 131 + consumableItemCatalog *masterdata.ConsumableItemCatalog, 129 132 gameConfig *masterdata.GameConfig, 130 133 sideStoryCatalog *masterdata.SideStoryCatalog, 131 134 bigHuntCatalog *masterdata.BigHuntCatalog, ··· 163 166 pb.RegisterCharacterServiceServer(srv, service.NewCharacterServiceServer(userStore, userStore, characterRebirthCatalog, gameConfig)) 164 167 pb.RegisterCompanionServiceServer(srv, service.NewCompanionServiceServer(userStore, userStore, companionCatalog, gameConfig)) 165 168 pb.RegisterMaterialServiceServer(srv, service.NewMaterialServiceServer(userStore, userStore, materialCatalog, gameConfig)) 169 + pb.RegisterConsumableItemServiceServer(srv, service.NewConsumableItemServiceServer(userStore, userStore, consumableItemCatalog, gameConfig)) 166 170 pb.RegisterSideStoryQuestServiceServer(srv, service.NewSideStoryQuestServiceServer(userStore, userStore, sideStoryCatalog)) 167 171 pb.RegisterBigHuntServiceServer(srv, service.NewBigHuntServiceServer(userStore, userStore, bigHuntCatalog, questEngine)) 168 172 pb.RegisterRewardServiceServer(srv, service.NewRewardServiceServer(userStore, userStore, bigHuntCatalog, questEngine.Granter))
+7
server/cmd/lunar-tear/main.go
··· 120 120 } 121 121 log.Printf("material catalog loaded: %d materials", len(materialCatalog.All)) 122 122 123 + consumableItemCatalog, err := masterdata.LoadConsumableItemCatalog() 124 + if err != nil { 125 + log.Fatalf("load consumable item catalog: %v", err) 126 + } 127 + log.Printf("consumable item catalog loaded: %d items", len(consumableItemCatalog.All)) 128 + 123 129 costumeCatalog, err := masterdata.LoadCostumeCatalog(materialCatalog) 124 130 if err != nil { 125 131 log.Fatalf("load costume catalog: %v", err) ··· 184 190 characterRebirthCatalog, 185 191 companionCatalog, 186 192 materialCatalog, 193 + consumableItemCatalog, 187 194 gameConfig, 188 195 sideStoryCatalog, 189 196 bigHuntCatalog,
+31
server/internal/masterdata/consumableitem.go
··· 1 + package masterdata 2 + 3 + import ( 4 + "fmt" 5 + 6 + "lunar-tear/server/internal/utils" 7 + ) 8 + 9 + type ConsumableItemRow struct { 10 + ConsumableItemId int32 `json:"ConsumableItemId"` 11 + SellPrice int32 `json:"SellPrice"` 12 + } 13 + 14 + type ConsumableItemCatalog struct { 15 + All map[int32]ConsumableItemRow 16 + } 17 + 18 + func LoadConsumableItemCatalog() (*ConsumableItemCatalog, error) { 19 + rows, err := utils.ReadJSON[ConsumableItemRow]("EntityMConsumableItemTable.json") 20 + if err != nil { 21 + return nil, fmt.Errorf("load consumable item table: %w", err) 22 + } 23 + 24 + catalog := &ConsumableItemCatalog{ 25 + All: make(map[int32]ConsumableItemRow, len(rows)), 26 + } 27 + for _, row := range rows { 28 + catalog.All[row.ConsumableItemId] = row 29 + } 30 + return catalog, nil 31 + }
+75
server/internal/service/consumableitem.go
··· 1 + package service 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "log" 7 + 8 + pb "lunar-tear/server/gen/proto" 9 + "lunar-tear/server/internal/masterdata" 10 + "lunar-tear/server/internal/store" 11 + "lunar-tear/server/internal/userdata" 12 + ) 13 + 14 + type ConsumableItemServiceServer struct { 15 + pb.UnimplementedConsumableItemServiceServer 16 + users store.UserRepository 17 + sessions store.SessionRepository 18 + catalog *masterdata.ConsumableItemCatalog 19 + config *masterdata.GameConfig 20 + } 21 + 22 + func NewConsumableItemServiceServer(users store.UserRepository, sessions store.SessionRepository, catalog *masterdata.ConsumableItemCatalog, config *masterdata.GameConfig) *ConsumableItemServiceServer { 23 + return &ConsumableItemServiceServer{users: users, sessions: sessions, catalog: catalog, config: config} 24 + } 25 + 26 + func (s *ConsumableItemServiceServer) Sell(ctx context.Context, req *pb.ConsumableItemSellRequest) (*pb.ConsumableItemSellResponse, error) { 27 + log.Printf("[ConsumableItemService] Sell: %d item(s)", len(req.ConsumableItemPossession)) 28 + 29 + userId := currentUserId(ctx, s.users, s.sessions) 30 + 31 + oldUser, _ := s.users.SnapshotUser(userId) 32 + tracker := userdata.NewDeleteTracker(). 33 + Track("IUserConsumableItem", oldUser, userdata.SortedConsumableItemRecords, []string{"userId", "consumableItemId"}) 34 + 35 + snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) { 36 + totalGold := int32(0) 37 + for _, item := range req.ConsumableItemPossession { 38 + row, ok := s.catalog.All[item.ConsumableItemId] 39 + if !ok { 40 + log.Printf("[ConsumableItemService] Sell: unknown consumableItemId=%d, skipping", item.ConsumableItemId) 41 + continue 42 + } 43 + 44 + cur := user.ConsumableItems[item.ConsumableItemId] 45 + if cur < item.Count { 46 + log.Printf("[ConsumableItemService] Sell: insufficient consumableItemId=%d have=%d need=%d", item.ConsumableItemId, cur, item.Count) 47 + continue 48 + } 49 + 50 + user.ConsumableItems[item.ConsumableItemId] -= item.Count 51 + if user.ConsumableItems[item.ConsumableItemId] <= 0 { 52 + delete(user.ConsumableItems, item.ConsumableItemId) 53 + } 54 + 55 + gold := row.SellPrice * item.Count 56 + totalGold += gold 57 + log.Printf("[ConsumableItemService] Sell: consumableItemId=%d x%d -> %d gold", item.ConsumableItemId, item.Count, gold) 58 + } 59 + 60 + if totalGold > 0 { 61 + user.ConsumableItems[s.config.ConsumableItemIdForGold] += totalGold 62 + log.Printf("[ConsumableItemService] Sell: total gold +%d", totalGold) 63 + } 64 + }) 65 + if err != nil { 66 + return nil, fmt.Errorf("consumable item sell: %w", err) 67 + } 68 + 69 + tables := userdata.SelectTables(userdata.FullClientTableMap(snapshot), []string{"IUserConsumableItem"}) 70 + diff := tracker.Apply(snapshot, tables) 71 + 72 + return &pb.ConsumableItemSellResponse{ 73 + DiffUserData: diff, 74 + }, nil 75 + }
+10 -10
server/proto/consumableitem.proto
··· 6 6 7 7 package apb.api.consumableitem; 8 8 9 - service ConsumableitemService { 10 - rpc UseEffectItem (UseEffectItemRequest) returns (UseEffectItemResponse); 11 - rpc Sell (SellRequest) returns (SellResponse); 9 + service ConsumableItemService { 10 + rpc UseEffectItem (ConsumableItemUseEffectItemRequest) returns (ConsumableItemUseEffectItemResponse); 11 + rpc Sell (ConsumableItemSellRequest) returns (ConsumableItemSellResponse); 12 12 } 13 13 14 - message UseEffectItemRequest { 14 + message ConsumableItemUseEffectItemRequest { 15 15 int32 consumableItemId = 1; 16 16 int32 count = 2; 17 17 } 18 18 19 - message UseEffectItemResponse { 19 + message ConsumableItemUseEffectItemResponse { 20 20 map<string, apb.api.data.DiffData> diffUserData = 99; 21 21 } 22 22 23 - message SellRequest { 24 - repeated SellPossession consumableItemPossession = 1; 23 + message ConsumableItemSellRequest { 24 + repeated ConsumableItemSellPossession consumableItemPossession = 1; 25 25 } 26 26 27 - message SellPossession { 27 + message ConsumableItemSellPossession { 28 28 int32 consumableItemId = 1; 29 29 int32 count = 2; 30 30 } 31 31 32 - message SellResponse { 32 + message ConsumableItemSellResponse { 33 33 map<string, apb.api.data.DiffData> diffUserData = 99; 34 - } 34 + }