252 lines
6.6 KiB
Go

package voiceroomrocket
import (
"encoding/json"
"math"
"strings"
)
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"`
GiftTabRules []giftTabEnergyRule `json:"giftTabRules"`
}
type giftEnergyRule struct {
GiftID flexibleInt64 `json:"giftId"`
GiftIDs []flexibleInt64 `json:"giftIds"`
Enabled *bool `json:"enabled"`
Allow *bool `json:"allow"`
Energy int64 `json:"energy"`
EnergyPerUnit int64 `json:"energyPerUnit"`
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 {
return 0, "invalid_energy_rule"
}
base := calculateBaseGiftEnergy(event)
if base <= 0 {
return 0, "zero_energy"
}
if custom, ok, reason := applyGiftIDRule(event, base, rule); ok || reason != "" {
return custom, reason
}
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
}
energy := int64(math.Floor(float64(base) * ratio))
if energy <= 0 {
return 0, "zero_energy"
}
return energy, ""
}
func parseEnergyRule(raw string) (energyRuleConfig, error) {
raw = strings.TrimSpace(raw)
if raw == "" || raw == "null" || raw == "{}" {
return energyRuleConfig{}, nil
}
var rule energyRuleConfig
if err := json.Unmarshal([]byte(raw), &rule); err != nil {
return energyRuleConfig{}, err
}
return rule, nil
}
func applyGiftIDRule(event giftEvent, base int64, rule energyRuleConfig) (int64, bool, string) {
giftID := event.GiftConfig.ID.Int64()
if giftID <= 0 || len(rule.GiftRules) == 0 {
return 0, false, ""
}
for _, item := range rule.GiftRules {
if !giftRuleMatches(item, giftID) {
continue
}
if item.Enabled != nil && !*item.Enabled {
return 0, true, "gift_rule_disabled"
}
if item.Allow != nil && !*item.Allow {
return 0, true, "gift_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 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
}
for _, id := range rule.GiftIDs {
if id.Int64() == giftID {
return true
}
}
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)
if containsGiftToken(rule.BlockedGiftTypes, giftType) || containsGiftToken(rule.BlockedGiftTabs, giftTab) {
return false
}
if len(rule.AllowedGiftTypes) > 0 && !containsGiftToken(rule.AllowedGiftTypes, giftType) {
return false
}
if len(rule.AllowedGiftTabs) > 0 && !containsGiftToken(rule.AllowedGiftTabs, giftTab) {
return false
}
if isDefaultBlockedGiftToken(giftType) || isDefaultBlockedGiftToken(giftTab) {
return false
}
if giftType == "" {
return false
}
return giftType == rewardTypeGold
}
func containsGiftToken(list []string, token string) bool {
token = normalizeGiftToken(token)
if token == "" {
return false
}
for _, item := range list {
if normalizeGiftToken(item) == token {
return true
}
}
return false
}
func isDefaultBlockedGiftToken(token string) bool {
switch normalizeGiftToken(token) {
case "DIAMOND", "LUCKY", "ACTIVITY", "CP", "MAGIC", "FREE":
return true
default:
return false
}
}
func normalizeGiftToken(value string) string {
return strings.ToUpper(strings.TrimSpace(value))
}
func calculateBaseGiftEnergy(event giftEvent) int64 {
if actual := event.GiftValue.ActualAmount.Int64(); actual > 0 {
return actual
}
quantity := normalizedGiftQuantity(event)
giftCandy := event.GiftConfig.GiftCandy.Int64()
if giftCandy <= 0 {
return 0
}
return giftCandy * quantity * normalizedAcceptUserSize(event)
}
func calculateRawEnergy(event giftEvent) int64 {
return calculateBaseGiftEnergy(event)
}
func normalizedGiftQuantity(event giftEvent) int64 {
quantity := event.Quantity.Int64()
if quantity <= 0 {
return 1
}
return quantity
}
func normalizedAcceptUserSize(event giftEvent) int64 {
acceptUserSize := int64(countDistinctAcceptUsers(event.Accepts))
if acceptUserSize <= 0 {
return 1
}
return acceptUserSize
}