From c0d58525fede1bc4b01c399fe7bdf945dc2c5738 Mon Sep 17 00:00:00 2001 From: hy001 Date: Sun, 17 May 2026 00:47:27 +0800 Subject: [PATCH] feat: discount lucky gift rocket energy --- internal/service/voiceroomrocket/energy.go | 73 +++++++++++++++++-- .../service/voiceroomrocket/event_test.go | 47 ++++++++++++ 2 files changed, 114 insertions(+), 6 deletions(-) diff --git a/internal/service/voiceroomrocket/energy.go b/internal/service/voiceroomrocket/energy.go index 3fcfc7b..df47451 100644 --- a/internal/service/voiceroomrocket/energy.go +++ b/internal/service/voiceroomrocket/energy.go @@ -7,12 +7,13 @@ import ( ) type energyRuleConfig struct { - GoldRatio float64 `json:"goldRatio"` - AllowedGiftTypes []string `json:"allowedGiftTypes"` - AllowedGiftTabs []string `json:"allowedGiftTabs"` - BlockedGiftTypes []string `json:"blockedGiftTypes"` - BlockedGiftTabs []string `json:"blockedGiftTabs"` - GiftRules []giftEnergyRule `json:"giftRules"` + GoldRatio float64 `json:"goldRatio"` + AllowedGiftTypes []string `json:"allowedGiftTypes"` + AllowedGiftTabs []string `json:"allowedGiftTabs"` + BlockedGiftTypes []string `json:"blockedGiftTypes"` + BlockedGiftTabs []string `json:"blockedGiftTabs"` + GiftRules []giftEnergyRule `json:"giftRules"` + GiftTabRules []giftTabEnergyRule `json:"giftTabRules"` } type giftEnergyRule struct { @@ -25,6 +26,16 @@ type giftEnergyRule struct { Ratio float64 `json:"ratio"` } +type giftTabEnergyRule struct { + GiftTab string `json:"giftTab"` + GiftTabs []string `json:"giftTabs"` + Enabled *bool `json:"enabled"` + Allow *bool `json:"allow"` + Energy int64 `json:"energy"` + EnergyPerUnit int64 `json:"energyPerUnit"` + Ratio float64 `json:"ratio"` +} + func resolveGiftEnergy(event giftEvent, snapshot configSnapshot) (int64, string) { rule, err := parseEnergyRule(snapshot.EnergyRuleJSON) if err != nil { @@ -40,6 +51,9 @@ func resolveGiftEnergy(event giftEvent, snapshot configSnapshot) (int64, string) if !isAllowedByGiftTypeAndTab(event, rule) { return 0, "unsupported_gift" } + if custom, ok, reason := applyGiftTabRule(event, base, rule); ok || reason != "" { + return custom, reason + } ratio := rule.GoldRatio if ratio <= 0 { ratio = 1 @@ -98,6 +112,41 @@ func applyGiftIDRule(event giftEvent, base int64, rule energyRuleConfig) (int64, return 0, false, "" } +func applyGiftTabRule(event giftEvent, base int64, rule energyRuleConfig) (int64, bool, string) { + giftTab := normalizeGiftToken(event.GiftConfig.GiftTab) + if giftTab == "" || len(rule.GiftTabRules) == 0 { + return 0, false, "" + } + for _, item := range rule.GiftTabRules { + if !giftTabRuleMatches(item, giftTab) { + continue + } + if item.Enabled != nil && !*item.Enabled { + return 0, true, "gift_tab_rule_disabled" + } + if item.Allow != nil && !*item.Allow { + return 0, true, "gift_tab_rule_blocked" + } + quantity := normalizedGiftQuantity(event) + acceptUserSize := normalizedAcceptUserSize(event) + if item.Energy > 0 { + return item.Energy * quantity * acceptUserSize, true, "" + } + if item.EnergyPerUnit > 0 { + return item.EnergyPerUnit * quantity * acceptUserSize, true, "" + } + if item.Ratio > 0 { + energy := int64(math.Floor(float64(base) * item.Ratio)) + if energy <= 0 { + return 0, true, "zero_energy" + } + return energy, true, "" + } + return base, true, "" + } + return 0, false, "" +} + func giftRuleMatches(rule giftEnergyRule, giftID int64) bool { if rule.GiftID.Int64() == giftID { return true @@ -110,6 +159,18 @@ func giftRuleMatches(rule giftEnergyRule, giftID int64) bool { return false } +func giftTabRuleMatches(rule giftTabEnergyRule, giftTab string) bool { + if normalizeGiftToken(rule.GiftTab) == giftTab { + return true + } + for _, tab := range rule.GiftTabs { + if normalizeGiftToken(tab) == giftTab { + return true + } + } + return false +} + func isAllowedByGiftTypeAndTab(event giftEvent, rule energyRuleConfig) bool { giftType := normalizeGiftToken(event.GiftConfig.Type) giftTab := normalizeGiftToken(event.GiftConfig.GiftTab) diff --git a/internal/service/voiceroomrocket/event_test.go b/internal/service/voiceroomrocket/event_test.go index ee24c84..57363d9 100644 --- a/internal/service/voiceroomrocket/event_test.go +++ b/internal/service/voiceroomrocket/event_test.go @@ -263,6 +263,53 @@ func TestGiftEnergyRulesRejectUnsupportedAndAllowConfiguredGift(t *testing.T) { } } +func TestGiftTabEnergyRuleDiscountsLuckyGiftOnly(t *testing.T) { + service, db := newTestService(t) + ctx := context.Background() + seedRocketConfig(t, db) + seedLevelConfigs(t, db, []int64{1000, 2000, 3000, 4000, 5000, 6000}) + + if err := db.Model(&model.VoiceRoomRocketConfig{}). + Where("sys_origin = ?", "LIKEI"). + Update("energy_rule_json", `{"giftTabRules":[{"giftTab":"LUCKY_GIFT","ratio":0.1}]}`).Error; err != nil { + t.Fatalf("update energy rule: %v", err) + } + + luckyPayload := `{ + "trackId":"track-lucky-ratio", + "sysOrigin":"LIKEI", + "sendUserId":"1001", + "roomId":"9001", + "quantity":1, + "giftConfig":{"id":"11","giftCandy":100,"type":"GOLD","giftTab":"LUCKY_GIFT"}, + "createTime":` + strconvFormatMillis(time.Now()) + ` + }` + lucky, err := service.ProcessGiftPayload(ctx, luckyPayload) + if err != nil { + t.Fatalf("ProcessGiftPayload(lucky) error = %v", err) + } + if !lucky.Processed || lucky.AcceptedEnergy != 10 { + t.Fatalf("lucky = %+v, want 10 energy", lucky) + } + + ordinaryPayload := `{ + "trackId":"track-ordinary-ratio", + "sysOrigin":"LIKEI", + "sendUserId":"1001", + "roomId":"9001", + "quantity":1, + "giftConfig":{"id":"12","giftCandy":100,"type":"GOLD","giftTab":"ORDINARY"}, + "createTime":` + strconvFormatMillis(time.Now().Add(time.Second)) + ` + }` + ordinary, err := service.ProcessGiftPayload(ctx, ordinaryPayload) + if err != nil { + t.Fatalf("ProcessGiftPayload(ordinary) error = %v", err) + } + if !ordinary.Processed || ordinary.AcceptedEnergy != 100 { + t.Fatalf("ordinary = %+v, want 100 energy", ordinary) + } +} + func TestInRoomRewardWorkerSnapshotsSelectsAndGrants(t *testing.T) { gateway := newFakeRocketGateway() service, db, rdb, mr := newTestServiceWithRedis(t, gateway)