fix: 修复各种错误。

main
NorthLan 2 years ago
parent f5f2bc166f
commit 2ec0ceb880

@ -29,6 +29,14 @@ func AllScoreType() []ScoreType {
return result return result
} }
func AllRankType() []pbVars.RankType {
result := make([]pbVars.RankType, 0, len(rankAndScoreMap))
for rankType, _ := range rankAndScoreMap {
result = append(result, rankType)
}
return result
}
func addRankScore(rankType pbVars.RankType, scoreType ScoreType) { func addRankScore(rankType pbVars.RankType, scoreType ScoreType) {
rankAndScoreMap[rankType] = scoreType rankAndScoreMap[rankType] = scoreType
scoreAndRankMap[scoreType] = rankType scoreAndRankMap[scoreType] = rankType

@ -9,21 +9,6 @@ import (
var _ RankPvpModel = (*customRankPvpModel)(nil) var _ RankPvpModel = (*customRankPvpModel)(nil)
const (
RankTypeDamage = iota + 1
RankTypeDeDamage
RankTypeGeneral
RankTypeDeGeneral
RankTypeKillUnit
RankTypeDeKillUnit
RankTypeKillPlayer
RankTypeDeKillPlayer
RankTypeWin
RankTypeLost
RankTypeFirstBlood
RankTypeDeFirstBlood
)
const MaxRankN = 50 const MaxRankN = 50
type ( type (

@ -37,6 +37,8 @@ type (
FindGreaterByScore(ctx context.Context, score int64, scoreType ScoreType, limit int) ([]UserAndScore, error) FindGreaterByScore(ctx context.Context, score int64, scoreType ScoreType, limit int) ([]UserAndScore, error)
// FindScoreByType 根据类型获取用户分数 // FindScoreByType 根据类型获取用户分数
FindScoreByType(ctx context.Context, tx *gorm.DB, userId int64, scoreType []ScoreType) (map[string]int64, error) FindScoreByType(ctx context.Context, tx *gorm.DB, userId int64, scoreType []ScoreType) (map[string]int64, error)
// CleanByType 清空某字段
CleanByType(ctx context.Context, tx *gorm.DB, scoreType ScoreType) error
} }
UserAndScore struct { UserAndScore struct {
@ -169,3 +171,10 @@ func (m *customStatisticsPvpModel) FindScoreByType(ctx context.Context, tx *gorm
return result, nil return result, nil
} }
func (m *customStatisticsPvpModel) CleanByType(ctx context.Context, tx *gorm.DB, scoreType ScoreType) error {
db := gormx.WithTx(ctx, m.DB, tx).Session(&gorm.Session{AllowGlobalUpdate: true})
result := db.Table(m.table).
Update(string(scoreType), 0)
return gormx.WrapUpdateErr(result.Error, result.RowsAffected)
}

@ -5,7 +5,6 @@ import (
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormx" "git.noahlan.cn/northlan/ntools-go/gorm-zero/gormx"
"github.com/pkg/errors" "github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/plugin/optimisticlock"
"live-service/common/nerr" "live-service/common/nerr"
) )
@ -17,7 +16,7 @@ type (
UserCoinModel interface { UserCoinModel interface {
userCoinModel userCoinModel
// ChangeCoin 用户弹币变动 // ChangeCoin 用户弹币变动
ChangeCoin(ctx context.Context, tx *gorm.DB, userId int64, change int64) (int64, error) ChangeCoin(ctx context.Context, tx *gorm.DB, userId int64, change int64, ignoreNotEnough bool) (int64, error)
} }
customUserCoinModel struct { customUserCoinModel struct {
@ -34,15 +33,15 @@ func NewUserCoinModel(conn *gorm.DB) UserCoinModel {
func (m *customUserCoinModel) updateCoin(ctx context.Context, tx *gorm.DB, coin *UserCoin) error { func (m *customUserCoinModel) updateCoin(ctx context.Context, tx *gorm.DB, coin *UserCoin) error {
if coin.Coin < 0 { if coin.Coin < 0 {
return errors.New("无法将弹币更新至负数") coin.Coin = 0
} }
db := gormx.WithTx(ctx, m.DB, tx) db := gormx.WithTx(ctx, m.DB, tx)
result := db.Model(&coin).Updates(&UserCoin{Coin: coin.Coin, Version: optimisticlock.Version{Int64: 1}}) result := db.Model(&coin).Update("coin", coin.Coin)
return gormx.WrapUpdateErr(result.Error, result.RowsAffected) return gormx.WrapUpdateErr(result.Error, result.RowsAffected)
} }
func (m *customUserCoinModel) ChangeCoin(ctx context.Context, tx *gorm.DB, userId int64, change int64) (int64, error) { func (m *customUserCoinModel) ChangeCoin(ctx context.Context, tx *gorm.DB, userId int64, change int64, ignoreNotEnough bool) (int64, error) {
resp := change resp := change
err := gormx.WithRetry(VersionRetryCount, func() error { err := gormx.WithRetry(VersionRetryCount, func() error {
return m.Transact(tx, func(tx *gorm.DB) error { return m.Transact(tx, func(tx *gorm.DB) error {
@ -50,8 +49,12 @@ func (m *customUserCoinModel) ChangeCoin(ctx context.Context, tx *gorm.DB, userI
if err != nil { if err != nil {
if errors.Is(err, ErrNotFound) { if errors.Is(err, ErrNotFound) {
if change < 0 { if change < 0 {
if ignoreNotEnough {
change = 0
} else {
return nerr.NewError(nerr.UserCoinNotEnoughErr, "用户弹币不足") return nerr.NewError(nerr.UserCoinNotEnoughErr, "用户弹币不足")
} }
}
// 用户积分记录不存在,进行插入 // 用户积分记录不存在,进行插入
if err = m.Insert(ctx, tx, &UserCoin{ if err = m.Insert(ctx, tx, &UserCoin{
UserId: userId, UserId: userId,
@ -65,8 +68,12 @@ func (m *customUserCoinModel) ChangeCoin(ctx context.Context, tx *gorm.DB, userI
} }
} }
if data.Coin+change < 0 { if data.Coin+change < 0 {
if ignoreNotEnough {
data.Coin = 0
} else {
return nerr.NewError(nerr.UserCoinNotEnoughErr, "用户弹币不足") return nerr.NewError(nerr.UserCoinNotEnoughErr, "用户弹币不足")
} }
}
data.Coin += change data.Coin += change
if err = m.updateCoin(ctx, tx, data); err != nil { if err = m.updateCoin(ctx, tx, data); err != nil {
if errors.Is(err, gormx.ErrRowsAffectedZero) { if errors.Is(err, gormx.ErrRowsAffectedZero) {

@ -19,11 +19,7 @@ type (
// and implement the added methods in customUserEliteModel. // and implement the added methods in customUserEliteModel.
UserEliteModel interface { UserEliteModel interface {
userEliteModel userEliteModel
// FindMaxSort 寻找当前用户精英单位的最大Sort 最小值2 // FindByUserId 查找用户所有列表
FindMaxSort(ctx context.Context, tx *gorm.DB, userId int64) int64
// FindOneByUserIdSort 通过用户和排序号找寻精英单位
FindOneByUserIdSort(ctx context.Context, tx *gorm.DB, userId int64, sort int64) (*UserElite, error)
// FindByUserId 查找用户所有列表,按sort升序排列
FindByUserId(ctx context.Context, tx *gorm.DB, userId int64) ([]UserElite, error) FindByUserId(ctx context.Context, tx *gorm.DB, userId int64) ([]UserElite, error)
// Addon 添加新的或延长时间 // Addon 添加新的或延长时间
Addon(ctx context.Context, tx *gorm.DB, userId, eliteId int64, duration time.Duration, forever bool) error Addon(ctx context.Context, tx *gorm.DB, userId, eliteId int64, duration time.Duration, forever bool) error
@ -41,35 +37,10 @@ func NewUserEliteModel(conn *gorm.DB) UserEliteModel {
} }
} }
func (m *customUserEliteModel) FindMaxSort(ctx context.Context, tx *gorm.DB, userId int64) int64 {
db := gormx.WithTx(ctx, m.DB, tx)
var resp int64 = 1
db.Table(m.table).
Select("MAX(sort)").
Where("user_id = ?", userId).
Where("end_time > ?", now.BeginningOfDay()).Take(&resp)
return resp
}
func (m *customUserEliteModel) FindOneByUserIdSort(ctx context.Context, tx *gorm.DB, userId int64, sort int64) (*UserElite, error) {
db := gormx.WithTx(ctx, m.DB, tx)
var resp UserElite
err := db.Model(&UserElite{}).
Where("user_id = ? and sort = ?", userId, sort).Take(&resp).Error
err = gormx.WrapSelectErr(err)
if err != nil {
return nil, err
}
return &resp, nil
}
func (m *customUserEliteModel) FindByUserId(ctx context.Context, tx *gorm.DB, userId int64) ([]UserElite, error) { func (m *customUserEliteModel) FindByUserId(ctx context.Context, tx *gorm.DB, userId int64) ([]UserElite, error) {
var resp []UserElite var resp []UserElite
err := gormx.WithTx(ctx, m.DB, tx).Table(m.table). err := gormx.WithTx(ctx, m.DB, tx).Table(m.table).
Where("user_id = ?", userId). Where("user_id = ?", userId).Find(&resp).Error
Order("sort asc").Find(&resp).Error
err = gormx.WrapSelectErr(err) err = gormx.WrapSelectErr(err)
if err != nil { if err != nil {
return nil, err return nil, err
@ -88,13 +59,10 @@ func (m *customUserEliteModel) Addon(ctx context.Context, tx *gorm.DB, userId, e
today := now.BeginningOfDay() today := now.BeginningOfDay()
if userElite == nil { if userElite == nil {
// sort
maxSort := m.FindMaxSort(ctx, tx, userId)
err = m.Insert(ctx, tx, &UserElite{ err = m.Insert(ctx, tx, &UserElite{
Id: uuid.NextId(), Id: uuid.NextId(),
UserId: userId, UserId: userId,
EliteId: eliteId, EliteId: eliteId,
Sort: maxSort + 1,
Forever: BitBool(forever), Forever: BitBool(forever),
StartTime: today, StartTime: today,
EndTime: today.Add(duration), EndTime: today.Add(duration),
@ -117,7 +85,6 @@ func (m *customUserEliteModel) Addon(ctx context.Context, tx *gorm.DB, userId, e
Id: userElite.Id, Id: userElite.Id,
UserId: userId, UserId: userId,
EliteId: eliteId, EliteId: eliteId,
Sort: userElite.Sort,
Forever: BitBool(forever), Forever: BitBool(forever),
StartTime: today, StartTime: today,
EndTime: today.Add(duration), EndTime: today.Add(duration),

@ -39,7 +39,6 @@ type (
Id int64 `gorm:"column:id;primaryKey"` // 主键ID Id int64 `gorm:"column:id;primaryKey"` // 主键ID
UserId int64 `gorm:"column:user_id"` // 用户ID UserId int64 `gorm:"column:user_id"` // 用户ID
EliteId int64 `gorm:"column:elite_id"` // 精英单位ID EliteId int64 `gorm:"column:elite_id"` // 精英单位ID
Sort int64 `gorm:"column:sort"` // 排序号
Forever BitBool `gorm:"forever"` // 永久 Forever BitBool `gorm:"forever"` // 永久
StartTime time.Time `gorm:"column:start_time;default:null"` // 开始时间 StartTime time.Time `gorm:"column:start_time;default:null"` // 开始时间
EndTime time.Time `gorm:"column:end_time;default:null"` // 结束时间 EndTime time.Time `gorm:"column:end_time;default:null"` // 结束时间

@ -5,7 +5,6 @@ import (
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormx" "git.noahlan.cn/northlan/ntools-go/gorm-zero/gormx"
"github.com/pkg/errors" "github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/plugin/optimisticlock"
"live-service/common/nerr" "live-service/common/nerr"
) )
@ -18,7 +17,7 @@ type (
userIntegralModel userIntegralModel
UpdateIntegral(ctx context.Context, tx *gorm.DB, integral *UserIntegral) error UpdateIntegral(ctx context.Context, tx *gorm.DB, integral *UserIntegral) error
// ChangeIntegral 用户积分变动 // ChangeIntegral 用户积分变动
ChangeIntegral(ctx context.Context, tx *gorm.DB, userId int64, change int64) (int64, error) ChangeIntegral(ctx context.Context, tx *gorm.DB, userId int64, change int64, ignoreNotEnough bool) (int64, error)
} }
customUserIntegralModel struct { customUserIntegralModel struct {
@ -35,15 +34,15 @@ func NewUserIntegralModel(conn *gorm.DB) UserIntegralModel {
func (m *customUserIntegralModel) UpdateIntegral(ctx context.Context, tx *gorm.DB, integral *UserIntegral) error { func (m *customUserIntegralModel) UpdateIntegral(ctx context.Context, tx *gorm.DB, integral *UserIntegral) error {
if integral.Integral < 0 { if integral.Integral < 0 {
return errors.New("无法将积分更新至负数") integral.Integral = 0
} }
db := gormx.WithTx(ctx, m.DB, tx) db := gormx.WithTx(ctx, m.DB, tx)
result := db.Model(&integral).Updates(&UserIntegral{Integral: integral.Integral, Version: optimisticlock.Version{Int64: 1}}) result := db.Model(&integral).Update("integral", integral.Integral)
return gormx.WrapUpdateErr(result.Error, result.RowsAffected) return gormx.WrapUpdateErr(result.Error, result.RowsAffected)
} }
func (m *customUserIntegralModel) ChangeIntegral(ctx context.Context, tx *gorm.DB, userId int64, change int64) (int64, error) { func (m *customUserIntegralModel) ChangeIntegral(ctx context.Context, tx *gorm.DB, userId int64, change int64, ignoreNotEnough bool) (int64, error) {
resp := change resp := change
err := gormx.WithRetry(VersionRetryCount, func() error { err := gormx.WithRetry(VersionRetryCount, func() error {
return m.Transact(tx, func(tx *gorm.DB) error { return m.Transact(tx, func(tx *gorm.DB) error {
@ -51,8 +50,12 @@ func (m *customUserIntegralModel) ChangeIntegral(ctx context.Context, tx *gorm.D
if err != nil { if err != nil {
if errors.Is(err, ErrNotFound) { if errors.Is(err, ErrNotFound) {
if change < 0 { if change < 0 {
if ignoreNotEnough {
change = 0
} else {
return nerr.NewError(nerr.UserIntegralNotEnoughError, "用户积分不足") return nerr.NewError(nerr.UserIntegralNotEnoughError, "用户积分不足")
} }
}
// 用户积分记录不存在,进行插入 // 用户积分记录不存在,进行插入
if err = m.Insert(ctx, tx, &UserIntegral{ if err = m.Insert(ctx, tx, &UserIntegral{
UserId: userId, UserId: userId,
@ -66,8 +69,12 @@ func (m *customUserIntegralModel) ChangeIntegral(ctx context.Context, tx *gorm.D
} }
} }
if data.Integral+change < 0 { if data.Integral+change < 0 {
if ignoreNotEnough {
data.Integral = 0
} else {
return nerr.NewError(nerr.UserIntegralNotEnoughError, "用户积分不足") return nerr.NewError(nerr.UserIntegralNotEnoughError, "用户积分不足")
} }
}
data.Integral += change data.Integral += change
if err = m.UpdateIntegral(ctx, tx, data); err != nil { if err = m.UpdateIntegral(ctx, tx, data); err != nil {
if errors.Is(err, gormx.ErrRowsAffectedZero) { if errors.Is(err, gormx.ErrRowsAffectedZero) {

@ -49,12 +49,11 @@ func NewUserTitleModel(conn *gorm.DB) UserTitleModel {
func (m *customUserTitleModel) FindMaxSort(ctx context.Context, tx *gorm.DB, userId int64) int64 { func (m *customUserTitleModel) FindMaxSort(ctx context.Context, tx *gorm.DB, userId int64) int64 {
db := gormx.WithTx(ctx, m.DB, tx) db := gormx.WithTx(ctx, m.DB, tx)
var resp int64 = 1 var resp int64 = 0
db.Table(m.table). db.Table(m.table).
Select("MAX(sort)"). Select("MAX(sort)").
Where("user_id = ?", userId). Where("user_id = ?", userId).Take(&resp)
Where("end_time > ?", now.BeginningOfDay()).Take(&resp)
return resp return resp
} }

@ -10,10 +10,11 @@ Etcd:
NonBlock: true NonBlock: true
Log: Log:
Mode: console Mode: console
Path: logs/live-service
KeepDays: 7 KeepDays: 7
Level: info Level: info
DB: DB:
DataSource: root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true DataSource: root:root@tcp(127.0.0.1:3306)/dmgame-dev?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true
Kafka: Kafka:
UserCoinNotify: UserCoinNotify:
Addr: [ "127.0.0.1:9093" ] Addr: [ "127.0.0.1:9093" ]
@ -41,6 +42,41 @@ Rank:
Cron: Cron:
Update: "@every 10s" # 10s一次 Update: "@every 10s" # 10s一次
Persistence: "@every 10m" # 10min一次 Persistence: "@every 10m" # 10min一次
Submit:
# 未列举的榜
0:
Best: [30,10,8,6,5,5]
Consolation: 1
# 名将
3:
TitleId: 1000
Best: [50,30,20,15,10,8]
Consolation: 1
# 小兵终结者
5:
TitleId: 1001
Best: [50,30,20,15,10,8]
Consolation: 1
# 拆迁办
7:
TitleId: 1002
Best: [60,40,25.6,18,10,8]
Consolation: 1
# 获胜榜
9:
TitleId: 1003
Best: [45.6,23.4,15,10,8,6]
Consolation: 1
# 一血
11:
TitleId: 1004
Best: [66.6,45.6,28,18,10,6]
Consolation: 2
# 怒送一血
12:
TitleId: 1005
Best: [66.6,45.6,28,18,10,6]
Consolation: 2
GiftCollector: GiftCollector:
Enabled: false Enabled: false
Platforms: [ "bilibili" ] Platforms: [ "bilibili" ]
@ -62,19 +98,19 @@ Coin:
FreeToCoin: FreeToCoin:
bilibili: 0.01 # 价值1毛 bilibili: 0.01 # 价值1毛
Elite: Elite:
LiveDict: { "1": "1001", "2": "1002" } LiveDict: { "1": "0", "2": "1001", "3": "1002" }
Default: DefaultId: 0
Id: 0
Sort: 1
Items: Items:
- Id: 1001 - Id: 1001
PriceDay: 100 Sort: 2
PriceForever: 10000 PriceDay: 80
PriceForever: 26660
- Id: 1002 - Id: 1002
PriceDay: 100 Sort: 3
PriceForever: 10000 PriceDay: 60
PriceForever: 18888
Title: Title:
LiveDict: { "1": "3" } LiveDict: { "1": "2000" }
Items: Items:
- Id: 99999 - Id: 99999
Name: 无上意志 Name: 无上意志
@ -86,12 +122,19 @@ Title:
Name: 废物舰长 Name: 废物舰长
Type: custom Type: custom
- Id: 3 - Id: 3
Name: 无用之人 Name: Joe王
Type: default Type: custom
PriceDay: 50 - Id: 4
PriceForever: 100000 Name: 我是弟弟
Type: custom
- Id: 5
Name: 萌新导师
Type: custom
- Id: 6
Name: 群萌新
Type: custom
- Id: 1000 - Id: 1000
Name: 三军统帅 # 名将榜首 Name: 军神 # 名将榜首
Type: rank Type: rank
RankType: 3 RankType: 3
- Id: 1001 - Id: 1001
@ -114,6 +157,11 @@ Title:
Name: 求放过 # 被一血榜首 Name: 求放过 # 被一血榜首
Type: rank Type: rank
RankType: 12 RankType: 12
- Id: 2000
Name: 无用之人
Type: default
PriceDay: 50
PriceForever: 100000
GiftPackMap: GiftPackMap:
- PackType: starter - PackType: starter
PackName: 新手礼包 PackName: 新手礼包

@ -63,11 +63,11 @@ func (m *Manager) TransferCoin(ctx context.Context, req *pb.TransferUserCoinReq)
if req.TargetUserId == 0 { if req.TargetUserId == 0 {
return nerr.NewError(nerr.RequestParamError, "目标用户ID为空") return nerr.NewError(nerr.RequestParamError, "目标用户ID为空")
} }
coin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.UserId, -req.Transfer) coin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.UserId, -req.Transfer, false)
if err != nil { if err != nil {
return nerr.NewWithErr(err) return nerr.NewWithErr(err)
} }
targetCoin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.TargetUserId, req.Transfer) targetCoin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.TargetUserId, req.Transfer, false)
if err != nil { if err != nil {
return nerr.NewWithErr(err) return nerr.NewWithErr(err)
} }
@ -98,7 +98,7 @@ func (m *Manager) TransferCoin(ctx context.Context, req *pb.TransferUserCoinReq)
} }
func (m *Manager) ChangeCoin(ctx context.Context, tx *gorm.DB, req *ChangeCoinReq, reason pbVars.UserCoinChangedReason) (*ChangeCoinResp, error) { func (m *Manager) ChangeCoin(ctx context.Context, tx *gorm.DB, req *ChangeCoinReq, reason pbVars.UserCoinChangedReason) (*ChangeCoinResp, error) {
coin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.UserId, req.Change) coin, err := m.userCoinModel.ChangeCoin(ctx, tx, req.UserId, req.Change, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -122,7 +122,7 @@ func (m *Manager) ChangeCoinBatch(ctx context.Context, req []ChangeCoinReq, reas
resp := make(map[int64]ChangeCoinResp) resp := make(map[int64]ChangeCoinResp)
if err := m.userCoinModel.TransactCtx(ctx, nil, func(tx *gorm.DB) error { if err := m.userCoinModel.TransactCtx(ctx, nil, func(tx *gorm.DB) error {
for _, item := range req { for _, item := range req {
coin, err := m.userCoinModel.ChangeCoin(ctx, tx, item.UserId, item.Change) coin, err := m.userCoinModel.ChangeCoin(ctx, tx, item.UserId, item.Change, false)
if err != nil { if err != nil {
return err return err
} }

@ -5,15 +5,13 @@ import "github.com/pkg/errors"
type ( type (
Elite struct { Elite struct {
LiveDict map[int32]int64 // 直播间序号对应ID LiveDict map[int32]int64 // 直播间序号对应ID
Default struct { DefaultId int64 // 默认单位ID
Id int64
Sort int32
} // 默认
Items []EliteItem Items []EliteItem
} }
// EliteItem 精英单位 // EliteItem 精英单位
EliteItem struct { EliteItem struct {
Id int64 // 单位ID Id int64 // 单位ID
Sort int32 // 排序号
PriceDay int64 // 每天价格(弹币) PriceDay int64 // 每天价格(弹币)
PriceForever int64 // 永久价格 PriceForever int64 // 永久价格
} }
@ -52,6 +50,12 @@ type (
} }
} }
} }
// RankSubmit 排行榜结算配置
RankSubmit struct {
TitleId int64 // 称号奖励
Best []float64 // 弹币奖励(前n) 单位: 元
Consolation float64 // 安慰奖(后max-n) 单位: 元
}
GameConfig struct { GameConfig struct {
UserRetriever struct { UserRetriever struct {
Enabled bool // 是否开启 Enabled bool // 是否开启
@ -74,6 +78,7 @@ type (
Update string // 更新榜单 Update string // 更新榜单
Persistence string // 持久化 Persistence string // 持久化
} }
Submit map[int32]RankSubmit // 排行榜结算
} }
GiftCollector struct { GiftCollector struct {
Enabled bool // 是否开启 Enabled bool // 是否开启

@ -0,0 +1,172 @@
package coin
import (
"bufio"
"context"
"fmt"
"github.com/shopspring/decimal"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"live-service/app/user_center/model"
"log"
"os"
"regexp"
"strconv"
"strings"
"testing"
"time"
)
func TestA(t *testing.T) {
file, err := os.Open("C:\\Users\\NorthLan\\Desktop\\dmgame v3\\6月.txt")
if err != nil {
fmt.Println("读取文件失败")
return
}
defer file.Close()
regex, _ := regexp.Compile(`\d+`)
type db struct {
name string
value int64
}
jfs := make([]db, 0)
scanner := bufio.NewScanner(file)
l := 0
var tmpJ db
for scanner.Scan() {
l++
line := scanner.Text()
if l == 3 {
// 名字
tmpJ.name = strings.TrimSpace(line)
} else if l == 4 {
// 电池
battery, _ := strconv.ParseInt(regex.FindString(line), 10, 0)
tmpJ.value = battery
jfs = append(jfs, tmpJ)
//fmt.Println(battery)
l = 0
}
}
gormDb, err := gorm.Open(mysql.Open("root:root@tcp(127.0.0.1:3306)/dmgame-dev?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true"), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 5 * time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
),
})
//UserPlatformModel := model.NewUserPlatformModel(gormDb)
//UserIntegralModel := model.NewUserIntegralModel(gormDb)
UserCoinModel := model.NewUserCoinModel(gormDb)
gormDb.Transaction(func(tx *gorm.DB) error {
for _, tmpJ := range jfs {
var userId int64
if err := tx.Table("user_platform").
Select("user_id").
Where("p_uname = ?", tmpJ.name).Take(&userId).Error; err != nil {
continue
}
//fmt.Println(userId)
UserCoinModel.ChangeCoin(context.Background(), tx, userId, tmpJ.value, false)
//tx.Table("user_integral").
// Where("user_id = ?", userId).
// Update("integral", gorm.Expr("integral + ?", tmpJ.integral))
}
return nil
})
if err := scanner.Err(); err != nil {
fmt.Println("err", err)
}
}
func TestB(t *testing.T) {
gormDb, _ := gorm.Open(mysql.Open("root:root@tcp(127.0.0.1:3306)/dmgame-dev?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true"), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 5 * time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
),
})
//UserPlatformModel := model.NewUserPlatformModel(gormDb)
UserIntegralModel := model.NewUserIntegralModel(gormDb)
//UserCoinModel := model.NewUserCoinModel(gormDb)
ctx := context.Background()
var allCoin []model.UserCoin
err := gormDb.Model(&model.UserCoin{}).Find(&allCoin).Error
if err != nil {
panic(err)
}
err = gormDb.Transaction(func(tx *gorm.DB) error {
for _, coin := range allCoin {
_, err := UserIntegralModel.ChangeIntegral(ctx, tx, coin.UserId, -coin.Coin*100, true)
if err != nil {
return err
}
time.Sleep(10 * time.Millisecond)
}
return nil
})
if err != nil {
panic(err)
}
}
func TestC(t *testing.T) {
gormDb, _ := gorm.Open(mysql.Open("root:root@tcp(127.0.0.1:3306)/dmgame-dev?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true"), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 5 * time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
),
})
//UserPlatformModel := model.NewUserPlatformModel(gormDb)
//UserIntegralModel := model.NewUserIntegralModel(gormDb)
UserCoinModel := model.NewUserCoinModel(gormDb)
ctx := context.Background()
var allIntegral []model.UserIntegral
err := gormDb.Model(&model.UserIntegral{}).Find(&allIntegral).Error
if err != nil {
panic(err)
}
err = gormDb.Transaction(func(tx *gorm.DB) error {
for _, integral := range allIntegral {
change := decimal.NewFromInt(integral.Integral).Div(decimal.NewFromInt(500)).Round(0).IntPart()
_, err := UserCoinModel.ChangeCoin(ctx, tx, integral.UserId, change, true)
if err != nil {
return err
}
//time.Sleep(10 * time.Millisecond)
}
return nil
})
if err != nil {
panic(err)
}
}

@ -1,14 +0,0 @@
package integral
import (
"context"
"github.com/zeromicro/go-zero/core/logx"
"live-service/app/user_center/rpc/internal/svc"
)
type IntegralTemp struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}

@ -1,91 +0,0 @@
package integral
import (
"bufio"
"context"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"live-service/app/user_center/model"
"log"
"os"
"regexp"
"strconv"
"strings"
"testing"
"time"
)
func TestA(t *testing.T) {
file, err := os.Open("C:\\Users\\NorthLan\\Desktop\\dmgame v2\\5月.txt")
if err != nil {
fmt.Println("读取文件失败")
return
}
defer file.Close()
regex, _ := regexp.Compile(`\d+`)
type jf struct {
name string
integral int64
}
jfs := make([]jf, 0)
scanner := bufio.NewScanner(file)
l := 0
var tmpJ jf
for scanner.Scan() {
l++
line := scanner.Text()
if l == 3 {
// 名字
tmpJ.name = strings.TrimSpace(line)
} else if l == 4 {
// 电池
battery, _ := strconv.ParseInt(regex.FindString(line), 10, 0)
tmpJ.integral = battery * 100
jfs = append(jfs, tmpJ)
//fmt.Println(battery)
l = 0
}
}
gormDb, err := gorm.Open(mysql.Open("root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true"), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 5 * time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
),
})
//UserPlatformModel := model.NewUserPlatformModel(gormDb)
UserIntegralModel := model.NewUserIntegralModel(gormDb)
gormDb.Transaction(func(tx *gorm.DB) error {
for _, tmpJ := range jfs {
var userId int64
if err := tx.Table("user_platform").
Select("user_id").
Where("p_uname = ?", tmpJ.name).Take(&userId).Error; err != nil {
continue
}
//fmt.Println(userId)
UserIntegralModel.ChangeIntegral(context.Background(), tx, userId, tmpJ.integral)
//tx.Table("user_integral").
// Where("user_id = ?", userId).
// Update("integral", gorm.Expr("integral + ?", tmpJ.integral))
}
return nil
})
if err := scanner.Err(); err != nil {
fmt.Println("err", err)
}
}

@ -11,7 +11,7 @@ import (
pbVars "live-service/app/pb/vars" pbVars "live-service/app/pb/vars"
"live-service/app/user_center/model" "live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "sync"
"time" "time"
) )
@ -23,18 +23,38 @@ type (
Username string Username string
Avatar string Avatar string
} }
RangeItem struct {
UserId int64
Username string
Avatar string
Score int64
}
Range struct {
Type pbVars.RankType
Items []RangeItem
}
ZSetWithLock struct {
*zset.ZSetInt
sync.RWMutex
}
Job struct { Job struct {
ctx context.Context ctx context.Context
svcCtx *svc.ServiceContext svcCtx *svc.ServiceContext
// 实时排行榜(定期读取,半实时) // 实时排行榜(定期读取,半实时)
rankByTypeMap map[pbVars.RankType]*zset.ZSetInt rankByTypeMap map[pbVars.RankType]*ZSetWithLock
// 用户数据表内存缓存 // 用户数据表内存缓存
userCache *lru.Cache userCache *lru.Cache
} }
) )
func newZSetWithLock(scoreLessThan func(l, r int32) bool, rankN int) *ZSetWithLock {
return &ZSetWithLock{
ZSetInt: zset.NewZSetInt(scoreLessThan, rankN),
}
}
func InitRankJob(svcCtx *svc.ServiceContext) { func InitRankJob(svcCtx *svc.ServiceContext) {
lessFunc := func(l, r int32) bool { lessFunc := func(l, r int32) bool {
return l > r return l > r
@ -43,19 +63,19 @@ func InitRankJob(svcCtx *svc.ServiceContext) {
Service = &Job{ Service = &Job{
ctx: context.Background(), ctx: context.Background(),
svcCtx: svcCtx, svcCtx: svcCtx,
rankByTypeMap: map[pbVars.RankType]*zset.ZSetInt{ rankByTypeMap: map[pbVars.RankType]*ZSetWithLock{
pbVars.RankType_Damage: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_Damage: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_DeDamage: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_DeDamage: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_General: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_General: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_DeGeneral: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_DeGeneral: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_KillUnit: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_KillUnit: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_DeKillUnit: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_DeKillUnit: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_KillPlayer: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_KillPlayer: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_DeKillPlayer: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_DeKillPlayer: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_Win: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_Win: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_Lost: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_Lost: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_FirstBlood: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_FirstBlood: newZSetWithLock(lessFunc, model.MaxRankN),
pbVars.RankType_DeFirstBlood: zset.NewZSetInt(lessFunc, model.MaxRankN), pbVars.RankType_DeFirstBlood: newZSetWithLock(lessFunc, model.MaxRankN),
}, },
userCache: uc, userCache: uc,
} }
@ -108,11 +128,25 @@ func (j *Job) initJob() {
c.Start() c.Start()
} }
func (j *Job) CleanByType(rankType pbVars.RankType) bool {
rankZSet, _, err := j.getRankInstanceAndScoreType(rankType)
if err != nil {
return false
}
rankZSet.Lock()
defer rankZSet.Unlock()
rankZSet.Clear()
return true
}
func (j *Job) RankByScore(rankType pbVars.RankType, score int32) int32 { func (j *Job) RankByScore(rankType pbVars.RankType, score int32) int32 {
rankZSet, _, err := j.getRankInstanceAndScoreType(rankType) rankZSet, _, err := j.getRankInstanceAndScoreType(rankType)
if err != nil { if err != nil {
return 0 return 0
} }
rankZSet.Lock()
defer rankZSet.Unlock()
rank := rankZSet.RangeByScore(score, score) rank := rankZSet.RangeByScore(score, score)
if len(rank) > 0 { if len(rank) > 0 {
@ -121,51 +155,53 @@ func (j *Job) RankByScore(rankType pbVars.RankType, score int32) int32 {
return 0 return 0
} }
func (j *Job) RangeRankByType(rankType pbVars.RankType, topN int32) *pb.RankPvpResp { func (j *Job) RangeRankByType(rankType pbVars.RankType, topN int32) Range {
result := &pb.RankPvpResp{ result := Range{Type: rankType}
Type: rankType,
}
rankZSet, _, err := j.getRankInstanceAndScoreType(rankType) rankZSet, _, err := j.getRankInstanceAndScoreType(rankType)
if err != nil { if err != nil {
return result return result
} }
if topN > model.MaxRankN { if topN > model.MaxRankN {
topN = model.MaxRankN topN = model.MaxRankN
} }
rankZSet.Lock()
rank := rankZSet.RangeByRank(1, uint32(topN)) rank := rankZSet.RangeByRank(1, uint32(topN))
rankZSet.Unlock()
// 这里make 减少扩容次数 // 这里make 减少扩容次数
result.Items = make([]*pb.RankPvpResp_Item, 0, len(rank)) result.Items = make([]RangeItem, 0, len(rank))
for _, r := range rank { for _, r := range rank {
uid := r[0] uid := r[0]
score := r[1] score := r[1]
var item pb.RankPvpResp_Item var item RangeItem
if c, ok := j.userCache.Get(uid); ok { if c, ok := j.userCache.Get(uid); ok {
cached := c.(CachedUserInfo) cached := c.(CachedUserInfo)
item = pb.RankPvpResp_Item{ item = RangeItem{
Uid: cached.UserId, UserId: cached.UserId,
Uname: cached.Username, Username: cached.Username,
Score: score, Score: score,
Avatar: cached.Avatar, Avatar: cached.Avatar,
} }
} else { } else {
dbUser, err := j.svcCtx.UserPlatformModel.FindDisplayOneByUserId(j.ctx, uid) dbUser, err := j.svcCtx.UserPlatformModel.FindDisplayOneByUserId(j.ctx, uid)
if err != nil { if err != nil {
item = pb.RankPvpResp_Item{ item = RangeItem{
Uid: uid, UserId: uid,
Score: score, Score: score,
} }
} else { } else {
item = pb.RankPvpResp_Item{ item = RangeItem{
Uid: uid, UserId: uid,
Uname: dbUser.PUname, Username: dbUser.PUname,
Score: score, Score: score,
Avatar: dbUser.PAvatar, Avatar: dbUser.PAvatar,
} }
} }
} }
result.Items = append(result.Items, &item) result.Items = append(result.Items, item)
} }
return result return result
} }
@ -175,6 +211,9 @@ func (j *Job) readAndUpdate(rankType pbVars.RankType) {
if err != nil { if err != nil {
return return
} }
rankZSet.Lock()
defer rankZSet.Unlock()
rank := rankZSet.RangeByRank(1, model.MaxRankN) rank := rankZSet.RangeByRank(1, model.MaxRankN)
rankLen := len(rank) rankLen := len(rank)
@ -219,7 +258,11 @@ func (j *Job) persistence(rankType pbVars.RankType) {
if err != nil { if err != nil {
return return
} }
rankZSet.Lock()
rank := rankZSet.RangeByRank(1, model.MaxRankN) rank := rankZSet.RangeByRank(1, model.MaxRankN)
rankZSet.Unlock()
dbModel := make([]model.RankPvp, 0, len(rank)) dbModel := make([]model.RankPvp, 0, len(rank))
for _, r := range rank { for _, r := range rank {
uid := r[0] uid := r[0]
@ -241,8 +284,8 @@ func (j *Job) persistence(rankType pbVars.RankType) {
} }
} }
func (j *Job) getRankInstanceAndScoreType(rankType pbVars.RankType) (*zset.ZSetInt, model.ScoreType, error) { func (j *Job) getRankInstanceAndScoreType(rankType pbVars.RankType) (*ZSetWithLock, model.ScoreType, error) {
var rankZSet *zset.ZSetInt var rankZSet *ZSetWithLock
scoreType := model.ScoreTypeByRankType(rankType) scoreType := model.ScoreTypeByRankType(rankType)
rankZSet, _ = j.rankByTypeMap[rankType] rankZSet, _ = j.rankByTypeMap[rankType]
if rankZSet == nil { if rankZSet == nil {

@ -4,6 +4,7 @@ import (
"context" "context"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
"live-service/common/nerr"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -24,5 +25,21 @@ func NewRankPvpLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RankPvpLo
// rank // rank
func (l *RankPvpLogic) RankPvp(in *pb.RankPvpReq) (*pb.RankPvpResp, error) { func (l *RankPvpLogic) RankPvp(in *pb.RankPvpReq) (*pb.RankPvpResp, error) {
return Service.RangeRankByType(in.Type, in.TopN), nil if !l.svcCtx.GameConfig.Rank.Enabled {
return nil, nerr.NewError(nerr.RankNotEnabled, "排行榜功能未开启")
}
resp := &pb.RankPvpResp{}
rankRange := Service.RangeRankByType(in.Type, in.TopN)
resp.Type = rankRange.Type
resp.Items = make([]*pb.RankPvpResp_Item, 0, len(rankRange.Items))
for _, item := range rankRange.Items {
resp.Items = append(resp.Items, &pb.RankPvpResp_Item{
Uid: item.UserId,
Uname: item.Username,
Score: item.Score,
Avatar: item.Avatar,
})
}
return resp, nil
} }

@ -2,6 +2,16 @@ package rank
import ( import (
"context" "context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormx"
"github.com/jinzhu/now"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
"gorm.io/gorm"
pbVars "live-service/app/pb/vars"
"live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/common/coin_manager"
"live-service/common/nerr"
"time"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
@ -24,7 +34,119 @@ func NewRankPvpSubmitLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ran
} }
func (l *RankPvpSubmitLogic) RankPvpSubmit(in *pb.RankPvpSubmitReq) (*pb.RankPvpSubmitResp, error) { func (l *RankPvpSubmitLogic) RankPvpSubmit(in *pb.RankPvpSubmitReq) (*pb.RankPvpSubmitResp, error) {
// todo: add your logic here and delete this line resp := &pb.RankPvpSubmitResp{
Items: make([]*pb.RankPvpSubmitResp_Item, 0),
}
if in.AllRankType {
if err := l.svcCtx.Db.Transaction(func(tx *gorm.DB) error {
for _, rankType := range model.AllRankType() {
if item, err := l.rankByType(rankType, tx); err != nil {
return err
} else {
resp.Items = append(resp.Items, item)
}
}
return nil
}); err != nil {
return nil, errors.Wrap(nerr.NewWithErr(err), "结算排行榜失败")
}
} else {
// rankType判断
var existsRankType bool
for _, rankType := range model.AllRankType() {
if rankType == in.RankType {
existsRankType = true
break
}
}
if !existsRankType {
return nil, errors.Wrap(nerr.NewError(nerr.RankNotExists, "排行榜类型不存在(不对)"), "排行榜类型不存在(不对)")
}
if item, err := l.rankByType(in.RankType, nil); err != nil {
return nil, errors.Wrap(nerr.NewWithErr(err), "结算排行榜失败")
} else {
resp.Items = append(resp.Items, item)
}
}
return resp, nil
}
func (l *RankPvpSubmitLogic) rankByType(rankType pbVars.RankType, tx *gorm.DB) (*pb.RankPvpSubmitResp_Item, error) {
if !l.svcCtx.GameConfig.Rank.Enabled {
return nil, nerr.NewError(nerr.RankNotEnabled, "排行榜功能未开启")
}
// . 获取对应榜单列表(用户)
// . 称号奖励+弹币奖励
// . 清理对应榜的数据(数据库+内存rank)
rankTypeInt := int32(rankType)
resp := &pb.RankPvpSubmitResp_Item{
RankType: rankType,
Results: make([]*pb.RankPvpSubmitResp_Result, 0),
}
rsCfg := l.svcCtx.GameConfig.Rank.Submit
cfg, ok := rsCfg[rankTypeInt]
if !ok {
cfg = rsCfg[0]
}
titleCfg, _ := l.svcCtx.GameConfig.Title.FindTitleCfg(cfg.TitleId)
titleExists := titleCfg != nil
rmbToCoin := l.svcCtx.GameConfig.Coin.RMBToCoin
return &pb.RankPvpSubmitResp{}, nil if err := gormx.WithTx(l.ctx, l.svcCtx.Db, tx).Transaction(func(tx *gorm.DB) error {
rankRange := Service.RangeRankByType(rankType, model.MaxRankN)
if len(rankRange.Items) == 0 {
return nil
}
for i, item := range rankRange.Items {
tmpItem := &pb.RankPvpSubmitResp_Result{
UserId: item.UserId,
Username: item.Username,
Avatar: item.Avatar,
}
if i == 0 {
// 榜首 称号奖励 从今日持续到本周日早
if titleExists {
durationHour := now.With(now.Sunday()).BeginningOfDay().Sub(now.BeginningOfDay()).Hours()
err := l.svcCtx.UserTitleModel.Addon(l.ctx, tx, item.UserId, titleCfg.Id, titleCfg.Type,
time.Duration(durationHour)*time.Hour, false)
if err != nil {
return nerr.NewWithErr(err)
}
tmpItem.Title = titleCfg.Id
}
}
var coinAddon int64
if i < len(cfg.Best) {
// 前N奖励
coinAddon = decimal.NewFromFloat(rmbToCoin).Mul(decimal.NewFromFloat(cfg.Best[i])).Round(0).IntPart()
} else {
// 安慰奖
coinAddon = decimal.NewFromFloat(rmbToCoin).Mul(decimal.NewFromFloat(cfg.Consolation)).Round(0).IntPart()
}
_, err := l.svcCtx.CoinManager.ChangeCoin(l.ctx, tx, &coin_manager.ChangeCoinReq{
UserId: item.UserId,
Change: coinAddon,
}, pbVars.UserCoinChangedReason_EventRankSubmit)
if err != nil {
return nerr.NewWithErr(err)
}
tmpItem.Coin = coinAddon
// . 清理
if err = l.svcCtx.StatisticsPvpModel.CleanByType(l.ctx, tx, model.ScoreTypeByRankType(rankType)); err != nil {
if !errors.Is(err, gormx.ErrRowsAffectedZero) {
return nerr.NewWithErr(err)
}
}
if !Service.CleanByType(rankType) {
return nerr.NewError(nerr.RankSubmitErr, "清理内存排行榜数据失败")
}
resp.Results = append(resp.Results, tmpItem)
}
return nil
}); err != nil {
return nil, nerr.NewWithErr(err)
}
return resp, nil
} }

@ -0,0 +1,11 @@
package rank
import (
"fmt"
"github.com/jinzhu/now"
"testing"
)
func TestAAA(t *testing.T) {
fmt.Println(now.With(now.Sunday()).BeginningOfDay().Sub(now.With(now.Monday()).BeginningOfDay()).Hours())
}

@ -35,7 +35,7 @@ type (
} }
statPvPReportItem struct { statPvPReportItem struct {
*pb.StatPvPReportResp_Item respItem *pb.StatPvPReportResp_Item
uid int64 uid int64
uname string uname string
damage int64 damage int64
@ -56,61 +56,50 @@ func (l *StatPvpReportLogic) StatPvpReport(in *pb.StatPvPReportReq) (*pb.StatPvP
WinCamp: in.WinCamp, WinCamp: in.WinCamp,
BattleId: in.BattleId, BattleId: in.BattleId,
} }
winItems := make([]*statPvPReportItem, 0, len(in.WinItems))
lostItems := make([]*statPvPReportItem, 0, len(in.LostItems))
// 1. 计算评分 // 1. 计算评分
winSum := l.calcSum(in.WinItems, winItems) winSum, winItems := l.calcSum(in.WinItems)
lostSum := l.calcSum(in.LostItems, lostItems) lostSum, lostItems := l.calcSum(in.LostItems)
l.calcScoreResponse(winSum, winItems) l.calcScoreResponse(winSum, winItems)
l.calcScoreResponse(lostSum, lostItems) l.calcScoreResponse(lostSum, lostItems)
// 2. 评分排序 // 2. 评分排序
sort.Slice(winItems, func(i, j int) bool { sort.Slice(winItems, func(i, j int) bool {
return winItems[i].Score > winItems[j].Score return winItems[i].respItem.Score > winItems[j].respItem.Score
}) })
sort.Slice(lostItems, func(i, j int) bool { sort.Slice(lostItems, func(i, j int) bool {
return lostItems[i].Score > lostItems[j].Score return lostItems[i].respItem.Score > lostItems[j].respItem.Score
}) })
// 3. 添加position + 各项记录(可忽略错误) // 3. 添加position + 各项记录(可忽略错误)
err = l.reports(true, winItems) err = l.reports(true, winItems)
if err != nil { if err != nil {
l.Logger.Errorf("获胜PvP记录失败, err:%v", err) l.Logger.Errorf("获胜PvP记录失败, err:%+v", err)
} }
err = l.reports(false, lostItems) err = l.reports(false, lostItems)
if err != nil { if err != nil {
l.Logger.Errorf("战败PvP记录失败, err:%v", err) l.Logger.Errorf("战败PvP记录失败, err:%+v", err)
} }
// resp // resp
resp.WinItems = make([]*pb.StatPvPReportResp_Item, 0, len(winItems)) resp.WinItems = make([]*pb.StatPvPReportResp_Item, 0, len(winItems))
resp.LostItems = make([]*pb.StatPvPReportResp_Item, 0, len(lostItems)) resp.LostItems = make([]*pb.StatPvPReportResp_Item, 0, len(lostItems))
for _, item := range winItems { for _, item := range winItems {
resp.WinItems = append(resp.WinItems, &pb.StatPvPReportResp_Item{ resp.WinItems = append(resp.WinItems, item.respItem)
Uid: item.uid,
Uname: item.uname,
Position: item.Position,
Score: item.Score,
})
} }
for _, item := range lostItems { for _, item := range lostItems {
resp.LostItems = append(resp.LostItems, &pb.StatPvPReportResp_Item{ resp.LostItems = append(resp.LostItems, item.respItem)
Uid: item.uid,
Uname: item.uname,
Position: item.Position,
Score: item.Score,
})
} }
return resp, nil return resp, nil
} }
func (l *StatPvpReportLogic) calcSum(items []*pb.StatPvPReportReq_Item, out []*statPvPReportItem) sumType { func (l *StatPvpReportLogic) calcSum(items []*pb.StatPvPReportReq_Item) (sumType, []*statPvPReportItem) {
resp := make([]*statPvPReportItem, 0, len(items))
var sum sumType var sum sumType
for _, item := range items { for _, item := range items {
sum.damage += item.Damage sum.damage += item.Damage
sum.deDamage += item.DeDamage sum.deDamage += item.DeDamage
sum.killPlayer += item.KillPlayer sum.killPlayer += item.KillPlayer
out = append(out, &statPvPReportItem{ resp = append(resp, &statPvPReportItem{
uid: item.Uid, uid: item.Uid,
uname: item.Uname, uname: item.Uname,
damage: item.Damage, damage: item.Damage,
@ -124,31 +113,46 @@ func (l *StatPvpReportLogic) calcSum(items []*pb.StatPvPReportReq_Item, out []*s
isGeneral: item.IsGeneral, isGeneral: item.IsGeneral,
}) })
} }
return sum return sum, resp
} }
func (l *StatPvpReportLogic) calcScoreResponse(sum sumType, items []*statPvPReportItem) { func (l *StatPvpReportLogic) calcScoreResponse(sum sumType, items []*statPvPReportItem) {
for _, item := range items { for _, item := range items {
itemResp := &pb.StatPvPReportResp_Item{ itemResp := &pb.StatPvPReportResp_Item{
Uid: item.Uid, Uid: item.uid,
Uname: item.Uname, Uname: item.uname,
Score: 0, Score: 0,
} }
damageScore, _ := decimal.NewFromInt(item.damage). var damageScore float64
if sum.damage == 0 {
damageScore = 0
} else {
damageScore, _ = decimal.NewFromInt(item.damage).
Div(decimal.NewFromInt(sum.damage)). Div(decimal.NewFromInt(sum.damage)).
Mul(decimal.NewFromFloat32(0.3)). Mul(decimal.NewFromFloat32(0.3)).
Mul(decimal.NewFromInt(100)). Mul(decimal.NewFromInt(100)).
Round(1).Float64() Round(1).Float64()
deDamageScore, _ := decimal.NewFromInt(item.deDamage). }
var deDamageScore float64
if sum.damage == 0 {
deDamageScore = 0
} else {
deDamageScore, _ = decimal.NewFromInt(item.deDamage).
Div(decimal.NewFromInt(sum.deDamage)). Div(decimal.NewFromInt(sum.deDamage)).
Mul(decimal.NewFromFloat32(0.1)). Mul(decimal.NewFromFloat32(0.1)).
Mul(decimal.NewFromInt(100)). Mul(decimal.NewFromInt(100)).
Round(1).Float64() Round(1).Float64()
killPlayerScore, _ := decimal.NewFromInt(item.killPlayer). }
var killPlayerScore float64
if sum.killPlayer == 0 {
killPlayerScore = 0
} else {
killPlayerScore, _ = decimal.NewFromInt(item.killPlayer).
Div(decimal.NewFromInt(sum.killPlayer)). Div(decimal.NewFromInt(sum.killPlayer)).
Mul(decimal.NewFromFloat32(0.3)). Mul(decimal.NewFromFloat32(0.3)).
Mul(decimal.NewFromInt(100)). Mul(decimal.NewFromInt(100)).
Round(1).Float64() Round(1).Float64()
}
deKillUnit := item.deKillUnit deKillUnit := item.deKillUnit
if deKillUnit == 0 { if deKillUnit == 0 {
deKillUnit = 1 deKillUnit = 1
@ -175,14 +179,17 @@ func (l *StatPvpReportLogic) calcScoreResponse(sum sumType, items []*statPvPRepo
if item.isGeneral { if item.isGeneral {
itemResp.Score += 10 itemResp.Score += 10
} }
item.StatPvPReportResp_Item = itemResp if itemResp.Score < 0 {
itemResp.Score = 0
}
item.respItem = itemResp
} }
} }
func (l *StatPvpReportLogic) reports(win bool, items []*statPvPReportItem) error { func (l *StatPvpReportLogic) reports(win bool, items []*statPvPReportItem) error {
return l.svcCtx.StatisticsPvpModel.TransactCtx(l.ctx, nil, func(tx *gorm.DB) error { return l.svcCtx.StatisticsPvpModel.TransactCtx(l.ctx, nil, func(tx *gorm.DB) error {
for i, item := range items { for i, item := range items {
item.Position = int32(i + 1) item.respItem.Position = int32(i + 1)
props := &model.UpdateRecordProps{ props := &model.UpdateRecordProps{
Damage: item.damage, Damage: item.damage,
DeDamage: item.deDamage, DeDamage: item.deDamage,
@ -201,7 +208,7 @@ func (l *StatPvpReportLogic) reports(win bool, items []*statPvPReportItem) error
props.General = true props.General = true
} }
if err := l.svcCtx.StatisticsPvpModel.UpdateRecord(l.ctx, tx, item.Uid, props); err != nil { if err := l.svcCtx.StatisticsPvpModel.UpdateRecord(l.ctx, tx, item.uid, props); err != nil {
if errors.Is(err, gormx.ErrRowsAffectedZero) { if errors.Is(err, gormx.ErrRowsAffectedZero) {
// insert // insert
var ( var (

@ -50,9 +50,6 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
resp.Coin = coin resp.Coin = coin
nowTime := time.Now() nowTime := time.Now()
// 当前佩戴 称号/精英单位
var currentTitle pb.UserDetailsResp_TitleItem
var currentElite pb.UserDetailsResp_EliteItem
_ = l.svcCtx.Db.Transaction(func(tx *gorm.DB) error { _ = l.svcCtx.Db.Transaction(func(tx *gorm.DB) error {
if zhgUserDetails, err := l.svcCtx.ZhgUserDetailsModel.FindOne(l.ctx, tx, in.UserId); err == nil { if zhgUserDetails, err := l.svcCtx.ZhgUserDetailsModel.FindOne(l.ctx, tx, in.UserId); err == nil {
@ -62,7 +59,7 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
if cfg, err := l.svcCtx.GameConfig.Title.FindTitleCfg(dbTitle.TitleId); err == nil { if cfg, err := l.svcCtx.GameConfig.Title.FindTitleCfg(dbTitle.TitleId); err == nil {
name = cfg.Name name = cfg.Name
} }
currentTitle = pb.UserDetailsResp_TitleItem{ resp.CurrentTitle = &pb.UserDetailsResp_TitleItem{
Id: dbTitle.TitleId, Id: dbTitle.TitleId,
Name: name, Name: name,
Sort: int32(dbTitle.Sort), Sort: int32(dbTitle.Sort),
@ -72,9 +69,13 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
} }
if dbElite, err := l.svcCtx.UserEliteModel.FindOneByUserIdEliteId(l.ctx, tx, in.UserId, zhgUserDetails.Elite); err == nil { if dbElite, err := l.svcCtx.UserEliteModel.FindOneByUserIdEliteId(l.ctx, tx, in.UserId, zhgUserDetails.Elite); err == nil {
if !timex.DayExpire(nowTime, dbElite.EndTime, bool(dbElite.Forever)) { if !timex.DayExpire(nowTime, dbElite.EndTime, bool(dbElite.Forever)) {
currentElite = pb.UserDetailsResp_EliteItem{ var sort int32 = 2
if cfg, err := l.svcCtx.GameConfig.Elite.FindEliteCfg(dbElite.EliteId); err == nil {
sort = cfg.Sort
}
resp.CurrentElite = &pb.UserDetailsResp_EliteItem{
Id: dbElite.EliteId, Id: dbElite.EliteId,
Sort: int32(dbElite.Sort), Sort: sort,
Remain: timex.DayRemain(nowTime, dbElite.EndTime, bool(dbElite.Forever)), Remain: timex.DayRemain(nowTime, dbElite.EndTime, bool(dbElite.Forever)),
} }
} }
@ -83,25 +84,25 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
return nil return nil
}) })
resp.CurrentTitle = &currentTitle
resp.CurrentElite = &currentElite
// 拥有 称号/精英单位 列表 // 拥有 称号/精英单位 列表
elites := make([]*pb.UserDetailsResp_EliteItem, 0) resp.Elites = make([]*pb.UserDetailsResp_EliteItem, 0)
if dbElites, err := l.svcCtx.UserEliteModel.FindByUserId(l.ctx, nil, in.UserId); err == nil { if dbElites, err := l.svcCtx.UserEliteModel.FindByUserId(l.ctx, nil, in.UserId); err == nil {
for _, item := range dbElites { for _, item := range dbElites {
if !timex.DayExpire(nowTime, item.EndTime, bool(item.Forever)) { if !timex.DayExpire(nowTime, item.EndTime, bool(item.Forever)) {
elites = append(elites, &pb.UserDetailsResp_EliteItem{ var sort int32 = 2
if cfg, err := l.svcCtx.GameConfig.Elite.FindEliteCfg(item.EliteId); err == nil {
sort = cfg.Sort
}
resp.Elites = append(resp.Elites, &pb.UserDetailsResp_EliteItem{
Id: item.EliteId, Id: item.EliteId,
Sort: int32(item.Sort), Sort: sort,
Remain: timex.DayRemain(nowTime, item.EndTime, bool(item.Forever)), Remain: timex.DayRemain(nowTime, item.EndTime, bool(item.Forever)),
}) })
} }
} }
} }
resp.Elites = elites
titles := make([]*pb.UserDetailsResp_TitleItem, 0) resp.Titles = make([]*pb.UserDetailsResp_TitleItem, 0)
if dbTitles, err := l.svcCtx.UserTitleModel.FindByUserId(l.ctx, nil, in.UserId); err == nil { if dbTitles, err := l.svcCtx.UserTitleModel.FindByUserId(l.ctx, nil, in.UserId); err == nil {
for _, item := range dbTitles { for _, item := range dbTitles {
if !timex.DayExpire(nowTime, item.EndTime, bool(item.Forever)) { if !timex.DayExpire(nowTime, item.EndTime, bool(item.Forever)) {
@ -109,7 +110,7 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
if cfg, err := l.svcCtx.GameConfig.Title.FindTitleCfg(item.TitleId); err == nil { if cfg, err := l.svcCtx.GameConfig.Title.FindTitleCfg(item.TitleId); err == nil {
name = cfg.Name name = cfg.Name
} }
titles = append(titles, &pb.UserDetailsResp_TitleItem{ resp.Titles = append(resp.Titles, &pb.UserDetailsResp_TitleItem{
Id: item.TitleId, Id: item.TitleId,
Name: name, Name: name,
Sort: int32(item.Sort), Sort: int32(item.Sort),
@ -118,7 +119,5 @@ func (l *GetUserDetailsLogic) GetUserDetails(in *pb.UserIdReq) (*pb.UserDetailsR
} }
} }
} }
resp.Titles = titles
return resp, nil return resp, nil
} }

@ -30,9 +30,12 @@ func NewBuyEliteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BuyElite
func (l *BuyEliteLogic) BuyElite(in *pb.EliteReq) (*pb.BuyEliteResp, error) { func (l *BuyEliteLogic) BuyElite(in *pb.EliteReq) (*pb.BuyEliteResp, error) {
elite, err := l.svcCtx.GameConfig.Elite.FindEliteCfgByLive(in.Sort) elite, err := l.svcCtx.GameConfig.Elite.FindEliteCfgByLive(in.Sort)
if err != nil { if err != nil {
// 待购买的精英单位不存在 return nil, nerr.NewError(nerr.EliteConfigNotFoundErr, err.Error())
return nil, errors.Wrapf(nerr.NewError(nerr.EliteConfigNotFoundErr, err.Error()), err.Error())
} }
if elite.Id == 0 {
return nil, nerr.NewError(nerr.UserBuyDefaultEliteErr, err.Error())
}
resp := &pb.BuyEliteResp{ resp := &pb.BuyEliteResp{
UserId: in.UserId, UserId: in.UserId,
EliteId: elite.Id, EliteId: elite.Id,

@ -33,9 +33,13 @@ func (l *ChangeEliteLogic) ChangeElite(in *pb.EliteReq) (*pb.ChangeEliteResp, er
resp := &pb.ChangeEliteResp{ resp := &pb.ChangeEliteResp{
UserId: in.UserId, UserId: in.UserId,
} }
eliteId := l.svcCtx.GameConfig.Elite.Default.Id eliteCfg, err := l.svcCtx.GameConfig.Elite.FindEliteCfgByLive(in.Sort)
if in.Sort != l.svcCtx.GameConfig.Elite.Default.Sort { if err != nil {
dbModel, err := l.svcCtx.UserEliteModel.FindOneByUserIdSort(l.ctx, nil, in.UserId, int64(in.Sort)) return nil, nerr.NewError(nerr.EliteConfigNotFoundErr, err.Error())
}
if eliteCfg.Id != l.svcCtx.GameConfig.Elite.DefaultId {
dbModel, err := l.svcCtx.UserEliteModel.FindOneByUserIdEliteId(l.ctx, nil, in.UserId, eliteCfg.Id)
if err != nil { if err != nil {
if errors.Is(err, gormx.ErrNotFound) { if errors.Is(err, gormx.ErrNotFound) {
return nil, errors.Wrap(nerr.NewError(nerr.UserEliteNotFoundErr, "用户没有此单位"), "用户没有此单位") return nil, errors.Wrap(nerr.NewError(nerr.UserEliteNotFoundErr, "用户没有此单位"), "用户没有此单位")
@ -46,13 +50,12 @@ func (l *ChangeEliteLogic) ChangeElite(in *pb.EliteReq) (*pb.ChangeEliteResp, er
if timex.DayExpire(time.Now(), dbModel.EndTime, bool(dbModel.Forever)) { if timex.DayExpire(time.Now(), dbModel.EndTime, bool(dbModel.Forever)) {
return nil, errors.Wrap(nerr.NewError(nerr.UserEliteExpiresErr, "待切换的精英单位已过期"), "待切换的精英单位已过期") return nil, errors.Wrap(nerr.NewError(nerr.UserEliteExpiresErr, "待切换的精英单位已过期"), "待切换的精英单位已过期")
} }
eliteId = dbModel.EliteId
} }
// 更新当前使用精英单位 // 更新当前使用精英单位
err := l.svcCtx.ZhgUserDetailsModel.Upsert(l.ctx, nil, &model.UpsertParam{ err = l.svcCtx.ZhgUserDetailsModel.Upsert(l.ctx, nil, &model.UpsertParam{
UserId: in.UserId, UserId: in.UserId,
Elite: &eliteId, Elite: &eliteCfg.Id,
}) })
if err != nil { if err != nil {
if !errors.Is(err, gormx.ErrRowsAffectedZero) { if !errors.Is(err, gormx.ErrRowsAffectedZero) {
@ -60,7 +63,7 @@ func (l *ChangeEliteLogic) ChangeElite(in *pb.EliteReq) (*pb.ChangeEliteResp, er
} }
} }
resp.EliteId = eliteId resp.EliteId = eliteCfg.Id
return resp, nil return resp, nil
} }

@ -2777,8 +2777,7 @@ type RankPvpSubmitResp_Result struct {
Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"`
Coin int64 `protobuf:"varint,4,opt,name=coin,proto3" json:"coin,omitempty"` // 获取到的积分数 Coin int64 `protobuf:"varint,4,opt,name=coin,proto3" json:"coin,omitempty"` // 获取到的积分数
Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` // 获取到的称号 Title int64 `protobuf:"varint,5,opt,name=title,proto3" json:"title,omitempty"` // 获取到的称号ID
TitleDuration int64 `protobuf:"varint,6,opt,name=titleDuration,proto3" json:"titleDuration,omitempty"` // 称号持续时间(单位: 秒,负数为无限长)
} }
func (x *RankPvpSubmitResp_Result) Reset() { func (x *RankPvpSubmitResp_Result) Reset() {
@ -2841,17 +2840,10 @@ func (x *RankPvpSubmitResp_Result) GetCoin() int64 {
return 0 return 0
} }
func (x *RankPvpSubmitResp_Result) GetTitle() string { func (x *RankPvpSubmitResp_Result) GetTitle() int64 {
if x != nil { if x != nil {
return x.Title return x.Title
} }
return ""
}
func (x *RankPvpSubmitResp_Result) GetTitleDuration() int64 {
if x != nil {
return x.TitleDuration
}
return 0 return 0
} }
@ -3209,166 +3201,164 @@ var file_user_center_proto_rawDesc = []byte{
0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72,
0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x52, 0x61,
0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c,
0x6c, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x22, 0xdb, 0x02, 0x0a, 0x11, 0x52, 0x61, 0x6c, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x22, 0xb4, 0x02, 0x0a, 0x11, 0x52, 0x61,
0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12,
0x30, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x30, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69,
0x74, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x74, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d,
0x73, 0x1a, 0xa4, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x1a, 0x7e, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75,
0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73,
0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x69, 0x6e,
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05,
0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74,
0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x74, 0x6c, 0x65,
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6d, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d,
0x12, 0x2d, 0x0a, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e,
0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12,
0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62,
0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72,
0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x72,
0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e,
0x70, 0x62, 0x2e, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65,
0x52, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6c,
0x6c, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0b, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x22, 0x9a, 0x01, 0x0a,
0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2b, 0x0a,
0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70,
0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x49,
0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x5d, 0x0a, 0x04, 0x49, 0x74,
0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52,
0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70,
0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
0x70, 0x6f, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x36, 0x0a, 0x08, 0x45, 0x6c, 0x69,
0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a,
0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x6f, 0x72,
0x74, 0x22, 0x76, 0x0a, 0x0c, 0x47, 0x69, 0x76, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65,
0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6c, 0x69,
0x74, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6c, 0x69, 0x74,
0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x18, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
0x52, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x0c, 0x42, 0x75, 0x79,
0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65,
0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63,
0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12,
0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x76, 0x0a, 0x0c, 0x47,
0x69, 0x76, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75,
0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65,
0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x02, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x69, 0x6e, 0x18,
0x65, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74,
0x76, 0x65, 0x72, 0x22, 0x84, 0x01, 0x0a, 0x0c, 0x42, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c,
0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x65, 0x1a, 0x6d, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x08, 0x72, 0x61, 0x6e,
0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x62,
0x2e, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08,
0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x52,
0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70,
0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
0x22, 0x92, 0x01, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x71,
0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x61, 0x72, 0x73,
0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54,
0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79,
0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x6e,
0x6b, 0x54, 0x79, 0x70, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61,
0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2b, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74,
0x65, 0x6d, 0x73, 0x1a, 0x5d, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x08, 0x72,
0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e,
0x70, 0x62, 0x2e, 0x76, 0x61, 0x72, 0x73, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65,
0x52, 0x08, 0x72, 0x61, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6f,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x12, 0x14, 0x0a, 0x05,
0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x63, 0x6f,
0x72, 0x65, 0x22, 0x36, 0x0a, 0x08, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16,
0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x22, 0x76, 0x0a, 0x0c, 0x47, 0x69,
0x76, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73,
0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72,
0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20,
0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08,
0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x65,
0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x76,
0x65, 0x72, 0x22, 0x70, 0x0a, 0x0c, 0x42, 0x75, 0x79, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65,
0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6c,
0x69, 0x74, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6c, 0x69,
0x74, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x76, 0x0a, 0x0c, 0x47, 0x69, 0x76, 0x65, 0x54, 0x69, 0x74, 0x6c,
0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07,
0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20,
0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x01, 0x28, 0x08, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x22, 0x84, 0x01, 0x0a,
0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x0f, 0x43, 0x68, 0x0c, 0x42, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a,
0x61, 0x6e, 0x67, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a,
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75,
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x22, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12,
0x36, 0x0a, 0x08, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74,
0x05, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x22, 0x57, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74,
0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x6c, 0x69,
0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18,
0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x0a, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x07, 0x65, 0x6c, 0x69, 0x74, 0x65, 0x49, 0x64, 0x22, 0x36, 0x0a, 0x08, 0x54, 0x69, 0x74, 0x6c,
0x2a, 0x28, 0x0a, 0x08, 0x47, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01,
0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,
0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x01, 0x32, 0xaf, 0x08, 0x0a, 0x0a, 0x75, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74,
0x73, 0x65, 0x72, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x14, 0x72, 0x65, 0x74, 0x22, 0x57, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52,
0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20,
0x72, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74,
0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69,
0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x34, 0x0a, 0x0e, 0x74, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x0d, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x28, 0x0a, 0x08, 0x47, 0x69, 0x66,
0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72,
0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63,
0x73, 0x70, 0x12, 0x36, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x42, 0x65, 0x10, 0x01, 0x32, 0xaf, 0x08, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x43, 0x65, 0x6e, 0x74,
0x79, 0x50, 0x55, 0x69, 0x64, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x14, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x6c,
0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e,
0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, 0x0b, 0x75, 0x73, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a,
0x65, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65,
0x73, 0x65, 0x72, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x34, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72,
0x65, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65,
0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x72, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72,
0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x0f, 0x67,
0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x67, 0x65, 0x74, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x42, 0x79, 0x50, 0x55, 0x69, 0x64, 0x12, 0x13,
0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x55, 0x73, 0x65, 0x72,
0x65, 0x72, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x52,
0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x10, 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x52, 0x65,
0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x73, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b,
0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x43, 0x6f, 0x69, 0x6e, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69,
0x6e, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x52, 0x65, 0x71,
0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69,
0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
0x72, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52,
0x65, 0x73, 0x70, 0x12, 0x2e, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
0x69, 0x66, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2e, 0x0a, 0x0c,
0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x12, 0x13, 0x2e, 0x70,
0x70, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x42, 0x75, 0x79, 0x4e, 0x6f, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65,
0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x0f,
0x42, 0x75, 0x79, 0x4e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x42, 0x75, 0x79, 0x4e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12,
0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x75, 0x79, 0x4e, 0x6f, 0x62, 0x69,
0x74, 0x50, 0x76, 0x70, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70,
0x53, 0x74, 0x61, 0x74, 0x50, 0x76, 0x50, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x50, 0x76, 0x70, 0x52, 0x65, 0x70,
0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x50, 0x76, 0x50, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x50, 0x76, 0x50,
0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x39, 0x0a, 0x0c, 0x64, 0x72, 0x61, 0x77, 0x47, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53,
0x69, 0x66, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x72, 0x61, 0x74, 0x61, 0x74, 0x50, 0x76, 0x50, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70,
0x77, 0x47, 0x69, 0x66, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x70, 0x12, 0x39, 0x0a, 0x0c, 0x64, 0x72, 0x61, 0x77, 0x47, 0x69, 0x66, 0x74, 0x50, 0x61, 0x63, 0x6b,
0x62, 0x2e, 0x44, 0x72, 0x61, 0x77, 0x47, 0x69, 0x66, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x72, 0x61, 0x77, 0x47, 0x69, 0x66, 0x74, 0x50, 0x61,
0x73, 0x70, 0x12, 0x2a, 0x0a, 0x07, 0x72, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x12, 0x0e, 0x2e, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x72, 0x61, 0x77, 0x47,
0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x69, 0x66, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x07, 0x72,
0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3c, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x12, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b,
0x0a, 0x0d, 0x72, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x50, 0x76, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b,
0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x50, 0x76, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3c, 0x0a, 0x0d, 0x72, 0x61, 0x6e, 0x6b, 0x50,
0x69, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61,
0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15,
0x75, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x50, 0x76, 0x70, 0x53, 0x75, 0x62, 0x6d, 0x69,
0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e,
0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x6b, 0x50, 0x76, 0x70, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x61,
0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x70, 0x62, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
0x2e, 0x47, 0x69, 0x76, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x45,
0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x69, 0x76, 0x65, 0x45, 0x6c,
0x2a, 0x0a, 0x08, 0x62, 0x75, 0x79, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x45,
0x2e, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x08, 0x62, 0x75, 0x79, 0x45,
0x75, 0x79, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x09, 0x67, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52,
0x69, 0x76, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x69, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x45, 0x6c, 0x69, 0x74, 0x65,
0x76, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x54, 0x69, 0x74, 0x6c,
0x42, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x08, 0x65, 0x12, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x69, 0x76, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65,
0x62, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c,
0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x54, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x08, 0x62, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c,
0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a,
0x67, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6c, 0x69, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73,
0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65,
0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13,
0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x6c, 0x69, 0x74, 0x65, 0x52,
0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x74,
0x6e, 0x67, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x06, 0x5a, 0x04, 0x6c, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x65, 0x71,
0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x74, 0x6c,
0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

@ -239,8 +239,7 @@ message RankPvpSubmitResp {
string username = 2; string username = 2;
string avatar = 3; string avatar = 3;
int64 coin = 4; // int64 coin = 4; //
string title = 5; // int64 title = 5; // ID
int64 titleDuration = 6; // (: ,)
} }
message Item { message Item {
pb.vars.RankType rankType = 1; // pb.vars.RankType rankType = 1; //

@ -39,6 +39,7 @@ const (
UserEliteExpiresErr // 用户精英单位过期 UserEliteExpiresErr // 用户精英单位过期
UserEliteNotFoundErr // 用户没有此单位 UserEliteNotFoundErr // 用户没有此单位
UserChangeEliteErr // 用户切换精英单位失败 UserChangeEliteErr // 用户切换精英单位失败
UserBuyDefaultEliteErr // 用户购买默认精英单位(不允许的事)
// UserTitleExpiresErr 用户称号相关 // UserTitleExpiresErr 用户称号相关
UserTitleExpiresErr // 用户称号过期 UserTitleExpiresErr // 用户称号过期
@ -59,6 +60,9 @@ const (
// RankStatisticsSelectError 排行相关 // RankStatisticsSelectError 排行相关
RankStatisticsSelectError // 获取统计数据失败 RankStatisticsSelectError // 获取统计数据失败
RankSubmitErr // 结算失败
RankNotEnabled // 排行榜功能未开启
RankNotExists // 排行榜不存在
// EliteConfigNotFoundErr 精英单位 // EliteConfigNotFoundErr 精英单位
EliteConfigNotFoundErr // 精英单位配置不存在 EliteConfigNotFoundErr // 精英单位配置不存在

Loading…
Cancel
Save