...
 
Commits (25)
......@@ -30,6 +30,7 @@ func GiftRemark() {
Payload: unmark.Payload,
MarkHiloGroup: unmark.MarkHiloGroup,
Mark: unmark.Mark, // 不能影响别的服务的mark状态
MarkHiloUser: unmark.MarkHiloUser,
}); err != nil {
model.Log.Errorf("FetchUnMarkEvent add unmark fail:%v", err)
continue
......
......@@ -177,6 +177,9 @@ type RoomInfo struct {
TotalConsume uint64 `json:"totalConsume"`
GameConfig *game_m.GameConfig `json:"gameConfig"`
Owner *user_cv.CvUserDetail `json:"owner"`
EntryEffectType int `json:"entryEffectType"` // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip
CpUserAvatar string `json:"cpUserAvatar"` // cp对象头像
CpLevel int `json:"cpLevel"` // cp等级
}
type SupportPageDetail struct {
......
......@@ -16,6 +16,7 @@ type EventGiftSend struct {
Payload []byte
Mark mysql.YesNo
MarkHiloGroup mysql.YesNo
MarkHiloUser mysql.YesNo
}
func (EventGiftSend) TableName() string {
......
......@@ -455,6 +455,7 @@ func GetMicUser(model *domain.Model, groupUuid string, i int) (*MicUser, error)
I: i,
ExternalId: micUser.ExternalId,
UserId: micUser.UserId,
CpUserId: micUser.CpUserId,
Forbid: micUser.Forbid,
Timestamp: micUser.Timestamp,
}, nil
......
......@@ -124,8 +124,10 @@ type MicUser struct {
I int
//麦中的人
ExternalId string
//
//用户id
UserId uint64
//用户cpId
CpUserId uint64
//静音 true:静音,false:没有静音
Forbid bool
//上麦的的时间戳
......@@ -184,11 +186,13 @@ func UpdateMicExpire(model *domain.Model, groupUuid string, externalId string) e
//2022-07-20 升级,判断是自己是否已经在别的麦上了
//const micInScript = "local flag = redis.call('SET', '{prefixGroupMicUser}', '{micUserStr}', 'ex', '{micExpire}', 'nx') if flag ~= false then redis.call('SETEX', '{prefixGroupUserMic}', '{micExpire}', '{groupUserStr}') return 1 end return 2 "
const micInScript = "local flag = redis.call('EXISTS', '{prefixGroupUserMic}') if flag == 0 then local flag1 = redis.call('SET', '{prefixGroupMicUser}', '{micUserStr}', 'ex', '{micExpire}', 'nx') if flag1 ~= false then redis.call('SETEX', '{prefixGroupUserMic}', '{micExpire}', '{groupUserStr}') return 1 end return 2 end return 3"
const micUpdateScript = "local flag = redis.call('EXISTS', '{prefixGroupUserMic}') if flag == 1 then local flag1 = redis.call('SET', '{prefixGroupMicUser}', '{micUserStr}', 'ex', '{micExpire}', 'xx') if flag1 ~= false then redis.call('SETEX', '{prefixGroupUserMic}', '{micExpire}', '{groupUserStr}') return 1 end return 2 end return 3"
//
//上麦(自己),
//规则:1:加锁了不能上麦 2:麦上有人,不能上麦
//cpUserId如果有
func (mic *Mic) In(userId uint64, externalId string) error {
// 群是否被封禁, 呃,,,呃,,,呃,,,
banned := GroupBanned{ImGroupId: mic.GroupUuid}
......@@ -220,27 +224,88 @@ func (mic *Mic) In(userId uint64, externalId string) error {
if err != nil {
return err
}
//让自己踢出去。
/* if str, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupUserInMic(externalId)).Result(); err != nil {
if err != redis2.Nil {
//加入到麦上可能有人的集合中。
groupMicHasIn(mic.model, mic.GroupUuid, userId)
//lua上麦,让麦上的人同人在麦上,保持原子性操作
//清理脚本,不然redis占用内存越来越高,并且不会释放
groupUserStr, err := userInMicToStr(mic.GroupUuid, mic.I, userId)
if err != nil {
return err
}
script := strings.Replace(strings.Replace(
strings.Replace(
strings.Replace(
strings.Replace(micInScript,
"{micExpire}", strconv.Itoa(expireMinute), -1),
"{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(mic.GroupUuid, mic.I), -1),
"{micUserStr}", micUserStr, -1),
"{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1),
"{groupUserStr}", groupUserStr, -1)
r, err := redis2.NewScript(script).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
mic.model.Log.Infof("micUser In micInScript:%v, result:%v", script, r)
d := r.(int64)
if err != nil {
return myerr.WrapErr(err)
}
} else {
if userInMic, err := strToUserInMic(str); err != nil {
return err
} else {
if micUser, err := GetMicUser(mic.model, userInMic.GroupUuid, userInMic.I); err != nil {
return err
} else {
if micUser != nil {
if err := micUser.LeaveByUser(userId, externalId); err != nil {
return err
if d == int64(2) {
return bizerr.GroupMicHasUser
}
if d == int64(3) {
return bizerr.GroupMicUserHasIn
}
//离开动作已结束,增加到队列中
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicInSignal,
Source: externalId,
}, false)
return nil
}
//上麦(自己),
//规则:1:加锁了不能上麦 2:麦上有人,不能上麦
//cpUserId如果有
func (mic *Mic) Update(userId uint64, externalId string, cpUserId uint64) (err error) {
defer func() {
if err != nil {
mic.model.Log.Errorf("MicUpdate fail,userId:%v,cpUserId:%v,err:%v", userId, cpUserId, err)
}
}()
// 群是否被封禁, 呃,,,呃,,,呃,,,
banned := GroupBanned{ImGroupId: mic.GroupUuid}
if err := banned.Get(mic.model); err != gorm.ErrRecordNotFound {
return bizerr.GroupIsBanned
}
//判断群组设置上的麦 是否被关闭
groupInfo, err := GetGroupInfo(mic.model, mic.GroupUuid)
if err != nil {
return err
}
if groupInfo.MicOn == false {
return bizerr.GroupInfoMicClosed
}
}*/
//麦被加锁了
if mic.Lock {
return bizerr.GroupMicLock
}
//设置值到redis
micUserStr, err := micUserToStr(MicUser{
GroupUuid: mic.GroupUuid,
I: mic.I,
ExternalId: externalId,
UserId: userId,
CpUserId: cpUserId,
Forbid: false,
Timestamp: time.Now().Unix(),
})
if err != nil {
return err
}
//加入到麦上可能有人的集合中。
groupMicHasIn(mic.model, mic.GroupUuid, userId)
......@@ -250,12 +315,15 @@ func (mic *Mic) In(userId uint64, externalId string) error {
if err != nil {
return err
}
//r, err := redis2.NewScript(micInScript).Run(context.Background(), redisCli.GetRedis(), []string{redis.GetPrefixGroupMicUser(mic.groupUuid), strconv.Itoa(mic.i), redis.GetPrefixGroupUserMic(), externalId}, micUserStr, groupUserStr).Result()
script := strings.Replace(strings.Replace(
strings.Replace(
strings.Replace(
strings.Replace(micInScript, "{micExpire}", strconv.Itoa(expireMinute), -1), "{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(mic.GroupUuid, mic.I), -1), "{micUserStr}", micUserStr, -1), "{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1), "{groupUserStr}", groupUserStr, -1)
//redisCli.GetRedis().ScriptFlush(context.Background())
strings.Replace(micUpdateScript,
"{micExpire}", strconv.Itoa(expireMinute), -1),
"{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(mic.GroupUuid, mic.I), -1),
"{micUserStr}", micUserStr, -1),
"{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1),
"{groupUserStr}", groupUserStr, -1)
r, err := redis2.NewScript(script).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
mic.model.Log.Infof("micUser In micInScript:%v, result:%v", script, r)
d := r.(int64)
......
......@@ -55,8 +55,11 @@ type MicUserData struct {
NobleLeave uint16 `json:"noble"` // 当前的贵族等级
HeadwearPicUrl string `json:"headwearPicUrl"`
HeadwearEffectUrl string `json:"headwearEffectUrl"`
HeadwearReverseEffectUrl string `json:"headwearReverseEffectUrl"` // 反转svga效果
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
MicEffect string `json:"micEffect"` //mic位置特效svga
HeadwearIcon string `json:"headwearIcon"` //头饰里面的小头像
}
type MicNumChangeContent struct {
......@@ -394,6 +397,11 @@ func getMicIContent(model *domain.Model, groupId string, i int) (MicContent, err
if err != nil {
return MicContent{}, err
}
var micEffect string
if micUser.CpUserId > 0 {
micEffect = "https://image.whoisamy.shop/hilo/resource/svga/mic_effect_cp.svga"
micUserData.MicEffect = micEffect
}
return MicContent{
GroupId: txGroupId,
I: mic.I,
......@@ -453,9 +461,11 @@ func getMicUserDatas(model *domain.Model, userIds []uint64) (map[uint64]*MicUser
}
var headwearPicUrl string
var headwearEffectUrl string
var reverseHeadwearEffectUrl string
if headwearUser, flag := headwearMap[id]; flag {
headwearPicUrl = resHeadwearMap[headwearUser.HeadwearId].PicUrl
headwearEffectUrl = resHeadwearMap[headwearUser.HeadwearId].EffectUrl
reverseHeadwearEffectUrl = resHeadwearMap[headwearUser.HeadwearId].ReverseEffectUrl
}
micUserDataMap[id] = &MicUserData{
Id: user.ID,
......@@ -468,6 +478,7 @@ func getMicUserDatas(model *domain.Model, userIds []uint64) (map[uint64]*MicUser
NobleLeave: nobleMap[id],
HeadwearPicUrl: headwearPicUrl,
HeadwearEffectUrl: headwearEffectUrl,
HeadwearReverseEffectUrl: reverseHeadwearEffectUrl,
SvipLevel: svips[id].SvipLevel,
Svip: rpc.CopySimpleSvip(svips[id]),
}
......@@ -495,6 +506,7 @@ func getMicUserData(model *domain.Model, userId uint64) (*MicUserData, error) {
var headwearPicUrl string
var headwearEffectUrl string
var headwearReverseEffectUrl string
headwear, err := user_m.GetUserHeadwearUsing(model, userId)
if err != nil {
......@@ -507,7 +519,13 @@ func getMicUserData(model *domain.Model, userId uint64) (*MicUserData, error) {
}
headwearPicUrl = resHeadwear.PicUrl
headwearEffectUrl = resHeadwear.EffectUrl
headwearReverseEffectUrl = resHeadwear.ReverseEffectUrl
}
var headwearIcon string
if cpRelation, _ := rpc.GetUserCpRelation(model, userId); len(cpRelation.CpUserAvatar) > 0 {
headwearIcon = cpRelation.CpUserAvatar
}
return &MicUserData{
Id: user.ID,
ExternalId: user.ExternalId,
......@@ -519,7 +537,9 @@ func getMicUserData(model *domain.Model, userId uint64) (*MicUserData, error) {
NobleLeave: nobleLeave,
HeadwearPicUrl: headwearPicUrl,
HeadwearEffectUrl: headwearEffectUrl,
HeadwearReverseEffectUrl: headwearReverseEffectUrl,
SvipLevel: svip.SvipLevel,
Svip: rpc.CopySimpleSvip(svip),
HeadwearIcon: headwearIcon,
}, nil
}
......@@ -14,6 +14,7 @@ type ResHeadwear struct {
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
ReverseEffectUrl mysql.Str
}
func GetResHeadwearById(model *domain.Model, id mysql.ID) (*ResHeadwear, error) {
......
......@@ -6,12 +6,14 @@ import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc"
uuid "github.com/satori/go.uuid"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/model/groupPower_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
......@@ -328,3 +330,100 @@ func (s *GroupMicService) IncrGroupPowerOnMicExpAndTime(groupId string, userId u
}
return nil
}
// 检查cp上麦
func (s *GroupMicService) CheckCpOnMic(groupUuid string) {
model := domain.CreateModelContext(s.svc.MyContext)
// 填充cp麦位
micNumType, err := group_m.GetMicNumType(model, groupUuid)
if err != nil {
return
}
_, micUsers, err := group_m.GetAllMic(groupUuid, micNumType)
if err != nil {
return
}
// userId->micIndex
var userMicIndex = make(map[uint64]int)
var userIds []uint64
for _, u := range micUsers {
userMicIndex[u.UserId] = u.I
userIds = append(userIds, u.UserId)
}
cpPairs, err := rpc.MGetUserCpPairs(model, userIds)
// 更新麦上cp的信息
if err != nil {
model.Log.Errorf("MGetUserCpPairs fail:%v", err)
return
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
model.Log.Errorf("GetUserMapByIds fail:%v", err)
return
}
for _, pairs := range cpPairs {
level := pairs[2]
if level < 5 { // cpLevel < 5 级别没有麦位特效
continue
}
userId := pairs[0]
cpUserId := pairs[1]
redisLock(redis_key.GetPrefixGroupMicUserInLock(userId), uuid.NewV4().String(), time.Second*2, func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
mic, err := group_m.GetMic(model, groupUuid, userMicIndex[userId])
if err != nil {
return err
}
return mic.Update(userId, users[userId].ExternalId, cpUserId)
})
redisLock(redis_key.GetPrefixGroupMicUserInLock(cpUserId), uuid.NewV4().String(), time.Second*2, func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
mic, err := group_m.GetMic(model, groupUuid, userMicIndex[cpUserId])
if err != nil {
return err
}
return mic.Update(cpUserId, users[cpUserId].ExternalId, userId)
})
}
return
}
// 检查cp下麦
func (s *GroupMicService) CheckCpLeaveMic(groupUuid string, leaveUid uint64) {
model := domain.CreateModelContext(s.svc.MyContext)
// 填充cp麦位
micNumType, err := group_m.GetMicNumType(model, groupUuid)
if err != nil {
return
}
_, micUsers, err := group_m.GetAllMic(groupUuid, micNumType)
if err != nil {
return
}
// userId->micIndex
var userMicIndex = make(map[uint64]int)
var cpUserId uint64
for _, u := range micUsers {
if u.UserId == leaveUid {
cpUserId = u.CpUserId
}
userMicIndex[u.UserId] = u.I
}
if cpUserId <= 0 {
return
}
user, err := user_m.GetUser(model, cpUserId)
if err != nil {
model.Log.Errorf("GetUser fail:%v", err)
return
}
redisLock(redis_key.GetPrefixGroupMicUserInLock(cpUserId), uuid.NewV4().String(), time.Second*2, func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
mic, err := group_m.GetMic(model, groupUuid, userMicIndex[cpUserId])
if err != nil {
return err
}
return mic.Update(cpUserId, user.ExternalId, 0)
})
return
}
......@@ -27,6 +27,7 @@ import (
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_mic_s"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
......@@ -232,6 +233,9 @@ func (s *GroupService) GroupIn(userId uint64, externalId string, groupUuid strin
NobleLevel uint16 `json:"nobleLevel"`
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
CpLevel int `json:"cpLevel"` // cp等级
CpUserAvatar string `json:"cpUserAvatar"` // cp用户头像
EntryEffectType int `json:"entryEffectType"` // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip
}
up := user_m.UserProperty{}
......@@ -246,6 +250,20 @@ func (s *GroupService) GroupIn(userId uint64, externalId string, groupUuid strin
if err != nil {
return err
}
var cpLevel int
var cpUserAvatar string
var cpEntryEffect bool
if cp, _ := rpc.GetUserCp(model, userId); cp != nil {
cpLevel = cp.CpLevel.Level
if cp.CpUserInfo.Avatar != nil {
cpUserAvatar = *cp.CpUserInfo.Avatar
}
for _, v := range cp.MyPrivilegeList {
if v.Type == 5 {
cpEntryEffect = true
}
}
}
r := UserParam{
Nick: user.Nick,
UserAvatar: user.Avatar,
......@@ -257,8 +275,27 @@ func (s *GroupService) GroupIn(userId uint64, externalId string, groupUuid strin
RidReceiverAvatar: properties[rides[userId]].ReceiverAvatar,
NobleLevel: nobleLevel,
Svip: rpc.CopySimpleSvip(svip),
CpLevel: cpLevel,
CpUserAvatar: cpUserAvatar,
}
rideId = r.RideId
// 进场特效类型
var entryEffectType int // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip ,顺序从小到大
if r.IsVip {
entryEffectType = 4
}
if r.NobleLevel > 0 {
entryEffectType = 3
}
for _, v := range r.Svip.Privileges {
if len(v.MysteryCode) > 0 {
entryEffectType = 2
}
}
if cpEntryEffect {
entryEffectType = 1
}
r.EntryEffectType = entryEffectType
buf, err := json.Marshal(r)
if err == nil {
......@@ -382,7 +419,8 @@ func (s *GroupService) RemoveZombie(model *domain.Model, groupId string) (string
//离开房间
func (s *GroupService) GroupLeave(userId uint64, externalId string, groupId string) error {
model := domain.CreateModelContext(s.svc.MyContext)
// check cp麦位置
group_mic_s.NewGroupPowerService(s.svc.MyContext).CheckCpLeaveMic(groupId, userId)
_, err := group_m.RoomLivingLeave(model, userId, externalId, groupId)
return err
}
......
......@@ -608,6 +608,38 @@ func GetRoomInfo(c *gin.Context) (*mycontext.MyContext, error) {
if err != nil {
model.Log.Errorf("GetRoomInfo: GetUserBase: %s", err.Error())
}
// 进场特效类型
var entryEffectType int // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip ,顺序从小到大
var cpEntryEffect bool
if cp, _ := rpc.GetUserCp(model, userId); cp != nil {
for _, v := range cp.MyPrivilegeList {
if v.Type == 5 {
cpEntryEffect = true
}
}
result.CpLevel = cp.CpLevel.Level
if cp.CpUserInfo != nil && cp.CpUserInfo.Avatar != nil {
result.CpUserAvatar = *cp.CpUserInfo.Avatar
}
}
if user, _ := user_cv.GetUserDetail(model, userId, userId); user != nil {
if user.IsVip {
entryEffectType = 4
}
if user.Noble.Level > 0 {
entryEffectType = 3
}
for _, v := range user.Svip.Privileges {
if len(v.MysteryCode) > 0 {
entryEffectType = 2
}
}
}
if cpEntryEffect {
entryEffectType = 1
}
result.EntryEffectType = entryEffectType
resp.ResponseOk(c, result)
return myContext, nil
......
......@@ -600,6 +600,8 @@ func GroupMicIn(c *gin.Context) (*mycontext.MyContext, error) {
} else {
resp.ResponseOk(c, nil)
}
// check cp 麦位置
go group_mic_s.NewGroupPowerService(myContext).CheckCpOnMic(groupUuid)
return myContext, nil
}
......@@ -699,6 +701,8 @@ func GroupMicLeave(c *gin.Context) (*mycontext.MyContext, error) {
return myContext, err
}
}
// check cp麦位置
group_mic_s.NewGroupPowerService(myContext).CheckCpLeaveMic(groupId, userId)
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicLeave(groupId, i, userId, externalId); err != nil {
return myContext, err
......
package test
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/rpc"
"testing"
)
func TestGetCpRelation(t *testing.T) {
cpRelation, err := rpc.GetUserCpRelation(domain.CreateModelNil(), 7642)
t.Logf("%v-%v", cpRelation, err)
}
func TestGetCpPairs(t *testing.T) {
cpPairs, err := rpc.MGetUserCpPairs(domain.CreateModelNil(), []uint64{7642, 4549})
t.Logf("%v-%v", cpPairs, err)
}
local flag = redis.call('EXISTS', 'group_user_in_mic_88913f81dc704b9e8e0a8b38956ee8b3')
if flag == 0
then local flag1 = redis.call('SET', 'group_mic_user_HTGS#a91394382_1', '{"GroupUuid":"HTGS#a91394382","I":1,"ExternalId":"88913f81dc704b9e8e0a8b38956ee8b3","UserId":7642,"CpUserId":4549,"Forbid":false,"Timestamp":1686305425}', 'ex', '43200', 'nx')
if flag1 ~= false then redis.call('SETEX', 'group_user_in_mic_88913f81dc704b9e8e0a8b38956ee8b3', '43200', '{"GroupUuid":"HTGS#a91394382","I":1,"UserId":7642}')
return 1 end
return 2 end
return 3
\ No newline at end of file