aozhiwei bbbc3d6401 1
2024-02-02 13:55:38 +08:00

691 lines
17 KiB
Go

package room
import (
"cs"
"f5"
"github.com/golang/protobuf/proto"
"main/common"
"main/constant"
"mt"
"q5"
"sort"
)
type room struct {
cs.MsgHandlerImpl
roomId string
roomIdx int64
curSortIdx int32
entry q5.ListHead
config struct {
mapId int32
zoneId int32
nodeId int32
passwd string
maxTeamNum int32
}
owner *member
roomState int32
startTime int64
startReason int32
disbandTime int64
disbandReason int32
teamUuidHash map[string]*team
teamIdHash map[int32]*team
obTeamUuidHash map[string]*team
obTeamIdHash map[int32]*team
members map[string]*member
startTimer *f5.TimerWp
delayDeleteTimer *f5.TimerWp
attacher *f5.TimerAttacher
gameStartNotifyMsg *cs.SMRoomGameStartNotify
}
func (this *room) init(roomId string, roomIdx int64, owner common.Player, msg *cs.CMCreateRoom) {
this.roomId = roomId
this.roomIdx = roomIdx
this.config.mapId = msg.GetMapId()
this.config.zoneId = msg.GetZoneId()
this.config.nodeId = msg.GetNodeId()
this.config.passwd = msg.GetPasswd()
this.config.maxTeamNum = constant.ROOM_MAX_TEAM_NUM
this.owner = newMember(this, owner)
this.addMember(this.owner)
this.addTeam(newTeam(this, this.genTeamId(), msg.GetTeamUuid(), this.owner))
}
func (this *room) unInit() {
for len(this.teamUuidHash) > 0 {
for _, t := range this.teamUuidHash {
t.unInit()
break
}
}
this.attacher.ClearTimers()
this.entry.DelInit()
delete(_roomMgr.idHash, this.roomId)
}
func (this *room) addMember(m *member) {
this.members[m.hum.GetAccountId()] = m
m.hum.SetRoom(this)
}
func (this *room) addTeam(t *team) {
t.sortIdx = this.genSortIdx()
this.teamUuidHash[t.teamUuid] = t
this.teamIdHash[t.teamId] = t
}
func (this *room) removeTeam(t *team) {
delete(this.teamUuidHash, t.teamUuid)
delete(this.teamIdHash, t.teamId)
}
func (this *room) addObTeam(t *team) {
t.obSortIdx = this.genSortIdx()
this.obTeamUuidHash[t.teamUuid] = t
this.obTeamIdHash[t.teamId] = t
}
func (this *room) removeObTeam(t *team) {
delete(this.obTeamUuidHash, t.teamUuid)
delete(this.obTeamIdHash, t.teamId)
}
func (this *room) genSortIdx() int32 {
this.curSortIdx += 1
return this.curSortIdx;
}
func (this *room) getMember(accountId string) *member {
m, ok := this.members[accountId]
if ok {
return m
}
return nil
}
func (this *room) getTeamByUuid(teamUuid string) *team {
t, ok := this.teamUuidHash[teamUuid]
if ok {
return t
}
return nil
}
func (this *room) getTeamById(teamId int32) *team {
t, ok := this.teamIdHash[teamId]
if ok {
return t
}
return nil
}
func (this *room) getObTeamByUuid(teamUuid string) *team {
t, ok := this.obTeamUuidHash[teamUuid]
if ok {
return t
}
return nil
}
func (this *room) getObTeamById(teamId int32) *team {
t, ok := this.obTeamIdHash[teamId]
if ok {
return t
}
return nil
}
func (this *room) getTeamNum() int32 {
return int32(len(this.teamUuidHash))
}
func (this *room) getObTeamNum() int32 {
return int32(len(this.obTeamUuidHash))
}
func (this *room) canJoin(member common.Player, msg *cs.CMJoinRoom) bool {
if this.started() {
return false
}
if member.GetRoom() != nil {
return false
}
if this.getMember(member.GetAccountId()) != nil {
return false
}
if this.config.passwd != msg.GetPasswd() {
return false
}
t := this.getTeamByUuid(msg.GetTeamUuid())
if t == nil {
t = this.getObTeamByUuid(msg.GetTeamUuid())
}
if t != nil {
if t.isFull() {
return false
} else {
return true
}
}
if msg.GetIsObserver() != 0 {
if this.isObTeamFull() {
return false
}
} else {
if this.isTeamFull() {
return false
}
}
return true
}
func (this *room) isTeamFull() bool {
return this.getTeamNum() >= this.config.maxTeamNum
}
func (this *room) isObTeamFull() bool {
return this.getObTeamNum() >= this.config.maxTeamNum
}
func (this *room) join(hum common.Player, msg *cs.CMJoinRoom) bool {
if !this.canJoin(hum, msg) {
return false
}
t := this.getTeamByUuid(msg.GetTeamUuid())
if t == nil {
t = this.getObTeamByUuid(msg.GetTeamUuid())
}
if t != nil {
if t.isFull() {
return false
}
m := newMember(this, hum)
this.addMember(m)
this.autoStartCountdown()
return true
}
m := newMember(this, hum)
this.addMember(m)
t = newTeam(this, this.genTeamId(), msg.GetTeamUuid(), m)
if msg.GetIsObserver() != 0 {
this.addObTeam(t)
} else {
this.addTeam(t)
this.autoStartCountdown()
}
return true
}
func (this *room) autoStartCountdown() {
if this.getTeamNum() != this.config.maxTeamNum {
return
}
var secondsRemaining int32 = 15
timer := f5.GetTimer()
timer.SetInterval(1000, func(e int32, args *q5.Args) {
if e == q5.TIMER_EXEC_EVENT {
if this.getTeamNum() != this.config.maxTeamNum {
timer.DeleteRunningTimer()
return
}
if secondsRemaining > 0 {
this.AutoStartGameCountdownNotify(secondsRemaining)
}
if secondsRemaining == 0 {
this.notifyGameStart()
timer.DeleteRunningTimer()
return
}
secondsRemaining--
}
})
}
func (this *room) fillMFRoom(hum common.Player, pb *cs.MFRoom) {
pb.RoomId = proto.String(this.roomId)
pb.MapId = proto.Int32(this.config.mapId)
pb.ZoneId = proto.Int32(this.config.zoneId)
if this.config.passwd != "" {
pb.HasPasswd = proto.Int32(1)
}
pb.PlayerNum = proto.Int32(int32(len(this.members)))
pb.PlayerMaxNum = proto.Int32(constant.ROOM_MAX_PLAYER_NUM)
pb.TeamNum = proto.Int32(int32(len(this.teamUuidHash)))
pb.TeamMaxNum = proto.Int32(constant.ROOM_MAX_TEAM_NUM)
m := this.getMember(hum.GetAccountId())
if m != nil {
pb.MyTeamId = proto.Int32(m.team.teamId)
}
pb.Owner = new(cs.MFMember)
this.owner.fillMFMember(pb.Owner)
}
func (this *room) fillMFCurrentRoom(hum common.Player, pb *cs.MFCurrentRoom) {
pb.RoomId = proto.String(this.roomId)
pb.MapId = proto.Int32(this.config.mapId)
pb.ZoneId = proto.Int32(this.config.zoneId)
if this.config.passwd != "" {
pb.HasPasswd = proto.Int32(1)
}
pb.PlayerNum = proto.Int32(int32(len(this.members)))
pb.PlayerMaxNum = proto.Int32(constant.ROOM_MAX_PLAYER_NUM)
pb.TeamNum = proto.Int32(int32(len(this.teamUuidHash)))
pb.TeamMaxNum = proto.Int32(constant.ROOM_MAX_TEAM_NUM)
m := this.getMember(hum.GetAccountId())
if m != nil {
pb.MyTeamId = proto.Int32(m.team.teamId)
}
pb.Owner = new(cs.MFMember)
this.owner.fillMFMember(pb.Owner)
q5.NewSlice(&pb.TeamList, 0, 10)
for _, t := range this.teamUuidHash {
pbT := &cs.MFTeam{}
t.fillMFTeam(pbT)
pbT.SortIdx = proto.Int32(t.sortIdx)
q5.AppendSlice(&pb.TeamList, pbT)
}
sort.Slice(pb.TeamList, func(i, j int) bool {
return pb.TeamList[i].GetSortIdx() < pb.TeamList[j].GetSortIdx()
})
q5.NewSlice(&pb.ObserverTeamList, 0, 10)
for _, t := range this.obTeamUuidHash {
pbT := &cs.MFTeam{}
t.fillMFTeam(pbT)
pbT.SortIdx = proto.Int32(t.obSortIdx)
q5.AppendSlice(&pb.ObserverTeamList, pbT)
}
sort.Slice(pb.ObserverTeamList, func(i, j int) bool {
return pb.ObserverTeamList[i].GetSortIdx() < pb.ObserverTeamList[j].GetSortIdx()
})
}
func (this *room) OnPlayerOffline(hum common.Player) {
}
func (this *room) OnPlayerOnline(hum common.Player) {
}
func (this *room) CMDisbandRoom(hdr *f5.MsgHdr, msg *cs.CMDisbandRoom) {
hum := hdr.Context.(common.Player)
rspMsg := &cs.SMDisbandRoom{}
if !this.isOwner(hum) {
rspMsg.Errcode = proto.Int32(1)
rspMsg.Errmsg = proto.String("insufficient permissions")
hum.SendMsg(rspMsg)
return
}
if this.roomState == ROOM_INIT_STATE {
this.doDisband(ROOM_DISBAND_1_REASON)
}
hum.SendMsg(rspMsg)
}
func (this *room) CMLeaveRoom(hdr *f5.MsgHdr, msg *cs.CMLeaveRoom) {
hum := hdr.Context.(common.Player)
m := this.getMember(hum.GetAccountId())
if m != nil && this.roomState == ROOM_INIT_STATE {
var removeMemberAccountId string
if this.isOwner(hum) {
nextOwner := this.getNextOwner()
if nextOwner == nil {
this.doDisband(ROOM_DISBAND_NO_NEXT_OWNER_REASON)
return
} else {
removeMemberAccountId = this.owner.hum.GetAccountId()
this.owner = nextOwner
}
} else {
removeMemberAccountId = hum.GetAccountId()
}
notifyMsg := &cs.SMRoomLeaveNotify{}
q5.NewSlice(&notifyMsg.AccountIds, 0, 1)
q5.AppendSlice(&notifyMsg.AccountIds, m.hum.GetAccountId())
this.broadcastMsg(notifyMsg)
this.notifyRoomInfo(hum)
this.removeMember(removeMemberAccountId)
}
}
func (this *room) CMModifyRoom(hdr *f5.MsgHdr, msg *cs.CMModifyRoom) {
hum := hdr.Context.(common.Player)
rspMsg := cs.SMModifyRoom{}
if this.isOwner(hum) && this.roomState == ROOM_INIT_STATE {
if msg.MapId != nil {
this.config.mapId = msg.GetMapId()
}
if msg.Passwd != nil {
this.config.passwd = msg.GetPasswd()
}
}
hum.SendMsg(&rspMsg)
this.notifyRoomInfo(hum)
}
func (this *room) CMStartGame(hdr *f5.MsgHdr, msg *cs.CMStartGame) {
hum := hdr.Context.(common.Player)
rspMsg := &cs.SMStartGame{}
if this.started() {
hum.SendMsg(rspMsg)
return
}
if this.canStart() {
this.doStart(1)
}
hum.SendMsg(rspMsg)
}
func (this *room) CMSetPrepare(hdr *f5.MsgHdr, msg *cs.CMSetPrepare) {
hum := hdr.Context.(common.Player)
m := this.getMember(hum.GetAccountId())
if m != nil && m != this.owner && this.roomState == ROOM_INIT_STATE {
m.state = MEMBER_READY_STATE
notifyMsg := &cs.SMRoomMemberChangeNotify{}
notifyMsg.Member = new(cs.MFMember)
m.fillMFMember(notifyMsg.Member)
this.broadcastMsg(notifyMsg)
}
}
func (this *room) CMKickoutTeam(hdr *f5.MsgHdr, msg *cs.CMKickoutTeam) {
hum := hdr.Context.(common.Player)
m := this.getMember(hum.GetAccountId())
t := this.getTeamByUuid(msg.GetTeamUuid())
if m == this.owner && t != nil && t != m.team && this.roomState == ROOM_INIT_STATE {
membersPtr := make([]*member, 0, t.members.Size())
t.members.ForEach(
func(data interface{}) bool {
if mPtr, ok := data.(*member); ok {
membersPtr = append(membersPtr, mPtr)
}
return true
})
notifyMsg := &cs.SMRoomKickoutNotify{}
for _, m2 := range membersPtr {
notifyMsg.AccountIds = append(notifyMsg.AccountIds, m2.hum.GetAccountId())
}
this.broadcastMsg(notifyMsg)
t.unInit()
this.notifyRoomInfo(hum)
}
}
func (this *room) CMKickoutMember(hdr *f5.MsgHdr, msg *cs.CMKickoutMember) {
hum := hdr.Context.(common.Player)
m := this.getMember(hum.GetAccountId())
target := this.getMember(msg.GetTargetId())
if m == this.owner && target != nil && this.roomState == ROOM_INIT_STATE {
notifyMsg := &cs.SMRoomKickoutNotify{}
notifyMsg.AccountIds = append(notifyMsg.AccountIds, msg.GetTargetId())
this.broadcastMsg(notifyMsg)
this.removeMember(target.hum.GetAccountId())
this.notifyRoomInfo(hum)
}
}
func (this *room) CMCloseNotify(hdr *f5.MsgHdr, msg *cs.CMCloseNotify) {
hum := hdr.Context.(common.Player)
m := this.getMember(hum.GetAccountId())
if m != nil {
m.closeGameStartNotify = true
}
}
func (this *room) broadcastMsg(msg proto.Message) {
for _, m := range this.members {
if m.hum.GetRoom() == this {
m.hum.SendMsg(msg)
}
}
}
func (this *room) autoStart() {
if this.roomState == ROOM_INIT_STATE {
if this.canStart() {
this.doStart(0)
} else {
this.doDisband(ROOM_DISBAND_DEFAULT_REASON)
}
}
}
func (this *room) started() bool {
return this.roomState == ROOM_STARTED_STATE
}
func (this *room) doDisband(reason int32) {
this.roomState = ROOM_DISBAND_STATE
this.disbandTime = f5.GetApp().GetNowSeconds()
this.disbandReason = reason
notifyMsg := &cs.SMRoomDisbandNotify{}
notifyMsg.RoomId = proto.String(this.roomId)
notifyMsg.Reason = proto.Int32(reason)
for _, m := range this.members {
if m.hum.GetRoom() == this {
m.hum.SendMsg(notifyMsg)
}
}
this.delayDeleteRoom()
}
func (this *room) doStart(reason int32) {
this.roomState = ROOM_STARTED_STATE
this.startTime = f5.GetApp().GetNowSeconds()
this.startReason = ROOM_AUTO_START_TYPE
f5.GetTimer().SetIntervalExWp(
1000,
func(e int32, args *q5.Args) {
if e == q5.TIMER_EXEC_EVENT {
if f5.GetApp().GetNowSeconds()-this.startTime <
int64(mt.Table.Config.Get().GetGameStartNotifyTime()) {
this.notifyGameStart()
}
}
},
this.attacher)
this.delayDeleteRoom()
}
func (this *room) viewable() bool {
return this.roomState == ROOM_INIT_STATE
}
func (this *room) GetRoomState() int32 {
return this.roomState
}
func (this *room) AutoStartGameCountdownNotify(seconds int32) {
notifyMsg := &cs.SMAutoStartGameCountdownNotify{}
notifyMsg.Seconds = proto.Int32(seconds)
this.broadcastMsg(notifyMsg)
}
func (this *room) notifyGameStart() {
if this.gameStartNotifyMsg == nil {
this.genGameStartNotifyMsg()
}
for _, m := range this.members {
// m.state == MEMBER_READY_STATE &&
if m.hum.GetRoom() == this &&
!m.closeGameStartNotify {
m.hum.SendMsg(this.gameStartNotifyMsg)
}
}
}
func (this *room) genGameStartNotifyMsg() {
if this.gameStartNotifyMsg != nil {
return
}
this.gameStartNotifyMsg = &cs.SMRoomGameStartNotify{}
this.gameStartNotifyMsg.ZoneId = proto.Int32(this.config.zoneId)
this.gameStartNotifyMsg.NodeId = proto.Int32(this.config.nodeId)
this.gameStartNotifyMsg.MapId = proto.Int32(this.config.mapId)
this.gameStartNotifyMsg.TeamUuid = proto.String(q5.ToString(this.roomIdx))
startInfo := struct {
ZoneId int32 `json:"zone_id"`
NodeId int32 `json:"node_id"`
RoomUuid string `json:"room_uuid"`
StartTime int32 `json:"start_time"`
TeamList []struct {
TeamUuid string `json:"team_uuid"`
Members []struct {
AccountId string `json:"account_id"`
} `json:"members"`
} `json:"team_list"`
ObList []struct {
AccountId string `json:"account_id"`
} `json:"ob_list"`
} {
ZoneId: this.config.zoneId,
NodeId: this.config.nodeId,
RoomUuid: q5.ToString(this.roomIdx),
StartTime: int32(this.startTime),
}
q5.NewSlice(&startInfo.TeamList, 0, 10)
for _, t := range this.teamUuidHash {
//if t.hasAlreadMember() {
{
ele := q5.NewSliceElement(&startInfo.TeamList)
ele.TeamUuid = t.teamUuid
q5.NewSlice(&ele.Members, 0, 4)
t.members.ForEach(
func(data interface{}) bool {
m := data.(*member)
//if m.state == MEMBER_READY_STATE {
ele2 := q5.NewSliceElement(&ele.Members)
ele2.AccountId = m.hum.GetAccountId()
//}
return true
})
}
}
q5.NewSlice(&startInfo.ObList, 0, 10)
for _, t := range this.obTeamUuidHash {
t.members.ForEach(
func(data interface{}) bool {
m := data.(*member)
ele := q5.NewSliceElement(&startInfo.ObList)
ele.AccountId = m.hum.GetAccountId()
return true
})
}
this.gameStartNotifyMsg.CustomRoomPayload = proto.String(
q5.Md5Str(q5.EncodeJson(&startInfo) + "520d8eAbB(8cf1^#$^&!@d833a42c820432PDAFE^^)") + "|" +
q5.EncodeJson(&startInfo))
}
func (this *room) canStart() bool {
return true
alreadyNum := 0
for _, t := range this.teamUuidHash {
if t.hasAlreadMember() {
alreadyNum++
}
}
return alreadyNum >= ROOM_MIN_START_TEAM_NUM
}
func (this *room) isOwner(hum common.Player) bool {
return this.owner.hum.GetAccountId() == hum.GetAccountId()
}
func (this *room) getNextOwner() *member {
var minT *member
var maxT *member
for i := int32(1); i <= this.config.maxTeamNum; i++ {
if i != this.owner.team.teamId {
if t, ok := this.teamIdHash[i]; ok {
ownerCandidate := t.getOwnerCandidate()
if ownerCandidate != nil {
if i < this.owner.team.teamId && minT == nil {
minT = ownerCandidate
}
if i > this.owner.team.teamId && maxT == nil {
maxT = ownerCandidate
}
}
}
}
}
if maxT != nil {
return maxT
} else {
return minT
}
}
func (this *room) genTeamId() int32 {
teamId := int32(-1)
for i := int32(1); i <= this.config.maxTeamNum; i++ {
if _, ok := this.teamIdHash[i]; !ok {
teamId = i
break
}
}
if teamId < 1 {
panic("room.genTeamId error")
}
return teamId
}
func (this *room) removeMember(accountId string) {
m := this.getMember(accountId)
if m != nil {
t := m.team
m.unInit()
if t.getMemberNum() <= 0 {
t.unInit()
}
}
}
func (this *room) notifyRoomInfo(hum common.Player) {
notifyMsg := &cs.SMRoomChangeNotify{}
notifyMsg.Room = new(cs.MFRoom)
this.fillMFRoom(hum, notifyMsg.Room)
this.broadcastMsg(notifyMsg)
}
func (this *room) delayDeleteRoom() {
if this.delayDeleteTimer != nil {
panic("errror dealyDeleteRoom")
}
this.delayDeleteTimer = f5.GetTimer().SetTimeoutExWp(
1000*mt.Table.Config.Get().GetDelayDeleteTime(),
func(e int32, args *q5.Args) {
if e == q5.TIMER_EXEC_EVENT {
this.unInit()
}
},
this.attacher)
}
func newRoom() *room {
r := new(room)
r.curSortIdx = 1
r.teamUuidHash = map[string]*team{}
r.teamIdHash = map[int32]*team{}
r.obTeamUuidHash = map[string]*team{}
r.obTeamIdHash = map[int32]*team{}
r.members = map[string]*member{}
r.entry.Init(r)
r.attacher = f5.GetTimer().NewTimerAttacher()
r.startTimer = f5.GetTimer().SetTimeoutExWp(
1000*mt.Table.Config.Get().GetAutoStartTime(),
func(e int32, args *q5.Args) {
if e == q5.TIMER_EXEC_EVENT {
r.autoStart()
}
},
r.attacher)
return r
}