257 lines
7.2 KiB
Go
257 lines
7.2 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/go-redis/redis/v8"
|
|
"gorm.io/gorm"
|
|
"samba/pkg/log"
|
|
"samba/stub"
|
|
"samba/util/rdbkey"
|
|
"samba/util/util"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
ResCoins = "coins" // 玩家金币
|
|
ResDiamond = "diamond"
|
|
ResTakeCoins = "takecoins"
|
|
ResClubUserScore = "score" // 俱乐部玩家身上的积分 t_club_member_info
|
|
ResClubCoins = "club_coins" // 玩家身上的俱乐部币(仅部长身上有值) t_user_rmoney
|
|
ResClubUserFreeScore = "free_score" // 官方赠送免费积分 t_club_member_info
|
|
ResClubUserInOutFreeScore = "inout_free_score" // 可提现的免费积分 t_club_member_info
|
|
|
|
)
|
|
|
|
var resourceMap = map[string]int{
|
|
ResCoins: 1000,
|
|
ResDiamond: 1001,
|
|
ResClubCoins: 1003,
|
|
ResTakeCoins: 1004,
|
|
ResClubUserScore: 1005,
|
|
ResClubUserFreeScore: 1006,
|
|
ResClubUserInOutFreeScore: 1007,
|
|
}
|
|
|
|
func ItemIdToRes(id stub.ItemId) string {
|
|
switch id {
|
|
case stub.Coin:
|
|
return ResCoins
|
|
case stub.ClubCoins:
|
|
return ResClubCoins
|
|
case stub.Diamonds:
|
|
return ResDiamond
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func ResToInt(res string) (int, error) {
|
|
resInt, ok := resourceMap[res]
|
|
if !ok {
|
|
return -1, fmt.Errorf("has not resource type:%v", res)
|
|
}
|
|
return resInt, nil
|
|
}
|
|
|
|
func IntToRes(res int) (string, error) {
|
|
for k, v := range resourceMap {
|
|
if v == res {
|
|
return k, nil
|
|
}
|
|
}
|
|
return "", fmt.Errorf("has not resource id:%v", res)
|
|
}
|
|
|
|
const (
|
|
ReasonEmote = "emote"
|
|
ReasonGame = "game"
|
|
ReasonEnter = "enter_room"
|
|
ReasonLeave = "leave_room"
|
|
ReasonSubsidy = "subsidy" // 破产补贴
|
|
//ReasonRobot = "robot"
|
|
)
|
|
|
|
type UserResource struct {
|
|
UID int64 `gorm:"column:user_id" json:"user_id"`
|
|
Coins int64 `gorm:"column:coins" json:"coins"` // 通用金币,通过商城购买得到
|
|
PayCoins int64 `gorm:"column:pay_coins" json:"pay_coins"` // 当前付费筹码数 已废弃
|
|
FreeCoins int64 `gorm:"column:free_coins" json:"free_coins"` // 当前免费筹码数 已废弃
|
|
PayTotal int64 `gorm:"column:pay_total" json:"pay_total"` // 累计付费筹码数 已废弃
|
|
BankCoins int64 `gorm:"column:bank_coins" json:"bank_coins"` //
|
|
Diamond int64 `gorm:"column:diamond" json:"diamond"` // 钻石
|
|
ClubCoins int64 `gorm:"column:club_coins" json:"club_coins"` // 俱乐部币
|
|
}
|
|
|
|
func (t *UserResource) TableName() string {
|
|
return "t_user_rmoney"
|
|
}
|
|
|
|
type UserResourceOp struct {
|
|
rdb *redis.Client
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewUserResourceOp() *UserResourceOp {
|
|
return &UserResourceOp{rdb: rdbMoney, db: userDB}
|
|
}
|
|
|
|
func (op *UserResourceOp) Load(uid int64) *UserResource {
|
|
res, err := util.Redis2Struct[UserResource](op.rdb, rdbkey.UserResourceKey(uid))
|
|
if err == nil {
|
|
return res
|
|
}
|
|
result := op.db.Where("user_id = ?", uid).First(&res)
|
|
if result.Error != nil {
|
|
// 没有该数据
|
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
|
res.UID = uid
|
|
result = op.db.Create(res)
|
|
if result.Error != nil {
|
|
log.Error(result.Error.Error())
|
|
return nil
|
|
}
|
|
} else {
|
|
log.Error(fmt.Sprintf("read db error:%v user:%v ", result.Error, uid))
|
|
return nil
|
|
}
|
|
}
|
|
// 回写redis
|
|
err = util.Struct2Redis(op.rdb, rdbkey.UserResourceKey(uid), res)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("serialize user:%v resource:%v error: %v", uid, res, err))
|
|
return nil
|
|
}
|
|
_ = rdbBaseInfo.Expire(context.Background(), rdbkey.UserResourceKey(uid), redis30day).Err()
|
|
return res
|
|
}
|
|
|
|
func (op *UserResourceOp) Get(uid int64, resType string) (int64, error) {
|
|
if resType == "" {
|
|
resType = ResCoins
|
|
}
|
|
res := op.Load(uid)
|
|
if res == nil {
|
|
return 0, fmt.Errorf("Load user:%v resource:%v fail", uid, resType)
|
|
}
|
|
switch resType {
|
|
case ResCoins:
|
|
return res.Coins, nil
|
|
case ResDiamond:
|
|
return res.Diamond, nil
|
|
case ResClubCoins:
|
|
return res.ClubCoins, nil
|
|
default:
|
|
return 0, fmt.Errorf("not add resource:%v user:%v resource:%v fail", resType, uid, resType)
|
|
}
|
|
}
|
|
|
|
func (op *UserResourceOp) GetTakeCoin(uid int64) (int64, error) {
|
|
val, err := op.rdb.HGet(context.Background(), rdbkey.UserResourceKey(uid), ResTakeCoins).Result()
|
|
if err == nil {
|
|
res, err := strconv.ParseInt(val, 10, 64)
|
|
return res, err
|
|
}
|
|
if errors.Is(err, redis.Nil) {
|
|
_ = op.Load(uid)
|
|
_, _ = op.AddTakeCoin(uid, 0)
|
|
return 0, nil
|
|
}
|
|
return 0, err
|
|
}
|
|
|
|
func (op *UserResourceOp) AddTakeCoin(uid int64, takeCoin int64) (int64, bool) {
|
|
res, err := op.rdb.HIncrBy(context.Background(), rdbkey.UserResourceKey(uid), ResTakeCoins, takeCoin).Result()
|
|
if err != nil {
|
|
log.Error(err.Error())
|
|
return 0, false
|
|
}
|
|
return res, true
|
|
}
|
|
|
|
func (op *UserResourceOp) Add(clubId int, uid, add int64, resType string) (int64, error) {
|
|
if resType == "" {
|
|
resType = ResCoins
|
|
}
|
|
|
|
res, err := op.Get(uid, resType)
|
|
if err != nil {
|
|
err = fmt.Errorf("user:%v add res:%v value:%v fail.err:%v", uid, resType, add, err.Error())
|
|
log.Error(err.Error())
|
|
return 0, err
|
|
}
|
|
//if res+add < 0 {
|
|
// err = fmt.Errorf("user:%v add res:%v add value:%v + current value:%v<0", uid, resType, add, res)
|
|
// log.Error(err.Error())
|
|
// return 0, err
|
|
//}
|
|
res, err = op.rdb.HIncrBy(context.Background(), rdbkey.UserResourceKey(uid), resType, add).Result()
|
|
if err != nil {
|
|
err = fmt.Errorf("user:%v add res:%v value:%v fail.err:%v", uid, resType, add, err.Error())
|
|
log.Error(err.Error())
|
|
return 0, err
|
|
}
|
|
_ = rdbBaseInfo.Expire(context.Background(), rdbkey.UserResourceKey(uid), redis30day).Err()
|
|
expr := fmt.Sprintf("%v + ?", resType)
|
|
err = op.db.Model(&UserResource{}).Where("user_id = ?", uid).Update(resType, gorm.Expr(expr, add)).Error
|
|
if err != nil {
|
|
err = fmt.Errorf("user:%v add res:%v value:%v fail.err:%v", uid, resType, add, err.Error())
|
|
log.Error(err.Error())
|
|
}
|
|
|
|
// 消耗俱乐部币添加等级分
|
|
if resType == ResClubCoins && add < 0 {
|
|
expType := "exp"
|
|
_, err = op.rdb.HIncrBy(context.Background(), rdbkey.ClubKey(clubId), expType, -add).Result()
|
|
if err != nil {
|
|
err = fmt.Errorf("key:%v add res:%v value:%v fail.err:%v", rdbkey.ClubKey(clubId), resType, -add, err.Error())
|
|
log.Error(err.Error())
|
|
return 0, err
|
|
}
|
|
expr := fmt.Sprintf("%v + ?", expType)
|
|
err = op.db.Model(&ClubInfo{}).Where("id = ?", clubId).Update(expType, gorm.Expr(expr, -add)).Error
|
|
if err != nil {
|
|
err = fmt.Errorf("club:%v add res:%v value:%v fail.err:%v", clubId, expType, -add, err.Error())
|
|
log.Error(err.Error())
|
|
}
|
|
}
|
|
return res, err
|
|
}
|
|
|
|
func CleanTakeCoin() {
|
|
cursor := uint64(0)
|
|
var keys []string
|
|
var err error
|
|
num := 0
|
|
for {
|
|
keys, cursor, err = rdbBaseInfo.Scan(context.Background(), cursor, "user|resource|*", 100).Result()
|
|
if err != nil {
|
|
log.Error(err.Error())
|
|
break
|
|
}
|
|
if cursor == 0 {
|
|
break
|
|
}
|
|
for _, key := range keys {
|
|
_, _ = rdbBaseInfo.HSet(context.Background(), key, ResTakeCoins, 0).Result()
|
|
log.Debug(fmt.Sprintf("clean key:%v takecoin", key))
|
|
num++
|
|
}
|
|
}
|
|
log.Debug(fmt.Sprintf("over.num:%v", num))
|
|
}
|
|
|
|
// UserIsBankrupt 用户是否达到破产条件
|
|
// offset: 可选参数,用户当前的金币+-某个值
|
|
func UserIsBankrupt(uid int64, offset ...int64) bool {
|
|
op := NewUserResourceOp()
|
|
coins, err := op.Get(uid, ResCoins)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
if len(offset) > 0 {
|
|
coins += offset[0]
|
|
}
|
|
return stub.IsBankrupt(coins)
|
|
}
|