| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- package frame
- import (
- "encoding/json"
- "fmt"
- "math/rand"
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/insecureframe/gate"
- audioroom "bet24.com/servers/micros/audioroom/proto"
- privateroom "bet24.com/servers/micros/privateroom/proto"
- "bet24.com/servers/user"
- "bet24.com/utils"
- )
- type WatchUser struct {
- UserIndex int32
- ChairId int
- UserId int
- }
- type ThreadsafeTable struct {
- tableSink TableSink
- tableSink_privateRoom TableSink_PrivateRoom
- users []int32
- tableId int
- chairCount int
- tableStatus int
- multiSetStatus int
- privateData string
- watchUsers []WatchUser
- startTime int64
- timers map[int]*time.Timer
- stopChan chan int
- timerChan chan int
- messageChan chan *threadsafe_message
- timerLock *sync.RWMutex
- owner int // 桌主,如果大于0表示私人房间,桌主离开后房间解散
- roomNo int
- dismissRequest []int
- dismissTimer *time.Timer
- stopped bool
- createTime int64
- tmpUserBets []audioroom.UserBet
- reportUserBetsTimer *time.Timer
- }
- func newThreadSafeTable(tableId int, owner int) *ThreadsafeTable {
- t := new(ThreadsafeTable)
- t.tableId = tableId
- t.timers = make(map[int]*time.Timer)
- t.stopChan = make(chan int)
- t.timerChan = make(chan int)
- t.timerLock = &sync.RWMutex{}
- t.messageChan = make(chan *threadsafe_message)
- t.owner = owner
- t.createTime = time.Now().Unix()
- return t
- }
- func (t *ThreadsafeTable) setRoomNo(roomNo int) {
- t.roomNo = roomNo
- }
- func (t *ThreadsafeTable) isPrivate() bool {
- return t.owner != 0
- }
- func (t *ThreadsafeTable) isMatch() bool {
- return t.owner == -1
- }
- func (t *ThreadsafeTable) setTableSink(sink TableSink) {
- t.tableSink = sink
- if t.isPrivate() {
- mid := (sink.(interface{})).(TableSink_PrivateRoom)
- t.tableSink_privateRoom = mid
- t.dismissRequest = make([]int, t.tableSink.OnGetChairCount())
- }
- t.clear()
- go t.mainLoop()
- }
- func (t *ThreadsafeTable) clear() {
- t.chairCount = t.tableSink.OnGetChairCount()
- t.users = make([]int32, t.chairCount)
- for i := 0; i < t.chairCount; i++ {
- t.users[i] = -1
- }
- }
- // 主线程
- func (t *ThreadsafeTable) mainLoop() {
- log.Debug("newThreadSafeTable tableId[%d] running", t.tableId)
- for {
- select {
- case <-t.stopChan:
- log.Debug("ThreadsafeTable tableId[%d] exiting mainLoop", t.tableId)
- t.tableSink.Destroy()
- t.killAllTimer()
- if t.isPrivate() {
- privateroom.ClosePrivateRoom(t.roomNo)
- t.roomNo = 0
- }
- return
- case timerId := <-t.timerChan:
- start := time.Now()
- t.tableSink.OnTimer(timerId)
- tc := time.Since(start)
- if tc.Milliseconds() >= 200 {
- log.Release("ThreadsafeTable.handleTimer[%d] run cost %v", timerId, tc)
- }
- case msg := <-t.messageChan:
- t.handleMsg(msg.Msg, msg.Data, msg.Callback)
- }
- }
- }
- func (t *ThreadsafeTable) handleMsg(msg, data string, callback chan byte) {
- if callback != nil {
- defer func() {
- callback <- 1
- }()
- }
- defer utils.TimeCost(fmt.Sprintf("ThreadsafeTable.handleMsg[%s],%s", msg, data))()
- switch msg {
- case "AddUser":
- var addUser msg_AddUser
- err := json.Unmarshal([]byte(data), &addUser)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.AddUser_safe(addUser.UserIndex, addUser.ChairId, addUser.Replay, addUser.ToWatch)
- case "RemoveUser":
- var removeUser msg_RemoveUser
- err := json.Unmarshal([]byte(data), &removeUser)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.RemoveUser_safe(removeUser.UserIndex, removeUser.ToWatch, removeUser.ChangeTable)
- case "dismiss":
- t.dismiss_safe()
- case "userReplay":
- var replay msg_UserReplay
- err := json.Unmarshal([]byte(data), &replay)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.userReplay_safe(replay.OldUserIndex, replay.NewUserIndex)
- case "dump":
- t.dump_safe()
- case "dumpScene":
- t.dumpScene_safe()
- case "dumpTimers":
- t.dumpTimers_safe()
- case "TableMessage":
- var tm msg_TableMessage
- err := json.Unmarshal([]byte(data), &tm)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.onTableMessage_safe(tm.UserIndex, tm.Msg, tm.Data)
- case "UserWatch":
- var watch msg_UserIndex
- err := json.Unmarshal([]byte(data), &watch)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.UserWatch(watch.UserIndex)
- case "SetUserReadyStatus":
- var ready msg_SetReadyStatus
- err := json.Unmarshal([]byte(data), &ready)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.SetUserReadyStatus(ready.UserIndex, ready.IsReady)
- case "SetBaseScore":
- var baseScore msg_SetBaseScore
- err := json.Unmarshal([]byte(data), &baseScore)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.setBaseScore_safe(baseScore.BaseScore)
- case "privateRoomStatusChanged":
- var statusChanged msg_statusChanged
- err := json.Unmarshal([]byte(data), &statusChanged)
- if err != nil {
- log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
- return
- }
- t.privateRoomStatusChanged_safe(statusChanged.OldStatus, statusChanged.NewStatus)
- case "privateRoomDismissed":
- t.privateRoomDismissed_safe()
- default:
- log.Debug("ThreadsafeTable.handleMsg unhandled %s", msg)
- }
- }
- func (t *ThreadsafeTable) getWatcherCount() int {
- return len(t.watchUsers)
- }
- func (t *ThreadsafeTable) getPlayerCount() int {
- count := 0
- for i := 0; i < t.chairCount; i++ {
- if t.users[i] != -1 {
- count++
- }
- }
- return count
- }
- func (t *ThreadsafeTable) getUserCount() int {
- return t.getPlayerCount() + t.getWatcherCount()
- }
- func (t *ThreadsafeTable) getEmptyChair() int {
- if t.tableSink.IsDual() {
- for i := 0; i < 3; i += 2 {
- if t.users[i] == -1 {
- return i
- }
- }
- return -1
- }
- // 随机分配
- start := rand.Intn(t.chairCount)
- for i := 0; i < t.chairCount; i++ {
- chair := (start + i) % t.chairCount
- if t.users[chair] == -1 {
- return chair
- }
- }
- return -1
- }
- func (t *ThreadsafeTable) isChairEmpty(chairId int) bool {
- if chairId < 0 || chairId >= t.chairCount {
- return false
- }
- if t.tableSink.IsDual() && chairId != 0 && chairId != 2 {
- log.Debug("ThreadsafeTable.isChairEmpty isdual and %d", chairId)
- return false
- }
- return t.users[chairId] == -1
- }
- func (t *ThreadsafeTable) isValidChair(chairId int) bool {
- return chairId >= 0 && chairId < t.tableSink.OnGetChairCount()
- }
- func (t *ThreadsafeTable) removeAllWatchUsers() {
- for _, v := range t.watchUsers {
- go gameFrame.setUserStatus(v.UserIndex, user.UserStatus_Free)
- }
- t.watchUsers = []WatchUser{}
- }
- func (t *ThreadsafeTable) getStartTime() int64 {
- if t.tableStatus != TableStatus_Playing {
- return 0
- }
- return time.Now().Unix() - t.startTime
- }
- func (t *ThreadsafeTable) isIdled() bool {
- return t.getStartTime() >= 300
- }
- func (t *ThreadsafeTable) isAllRobot() bool {
- return t.tableSink.IsAllRobot()
- }
- func (t *ThreadsafeTable) isFull() bool {
- if t.tableSink.IsDual() {
- for i := 0; i < 3; i += 2 {
- if t.users[i] == -1 {
- return false
- }
- }
- return true
- }
- for i := 0; i < t.chairCount; i++ {
- if t.users[i] == -1 {
- return false
- }
- }
- return true
- }
- func (t *ThreadsafeTable) isSameRoom(data string) bool {
- if len(data) == 0 {
- return true
- }
- return data == t.privateData
- }
- func (t *ThreadsafeTable) checkSameIp(userIp string) bool {
- // 百人场不限制
- if gameFrame.gameSink.GetChairCount() < 2 {
- return false
- }
- if t.ignoreSameIP() {
- return false
- }
- // 机器人不限制
- if userIp == "" || userIp == "127.0.0.1" {
- return false
- }
- // 2人场 不限制
- if t.tableSink.IsDual() {
- return false
- }
- for i := 0; i < t.chairCount; i++ {
- if t.users[i] == -1 {
- continue
- }
- usr := gate.GetUserInfo(t.users[i])
- if usr == nil {
- continue
- }
- if usr.GetUserIp() == userIp {
- return true
- }
- }
- // 如果有旁观也挡一下
- for _, v := range t.watchUsers {
- usr := gate.GetUserInfo(v.UserIndex)
- if usr == nil {
- continue
- }
- if usr.GetUserIp() == userIp {
- return true
- }
- }
- return false
- }
- func (t *ThreadsafeTable) canRemoveOneRobot() bool {
- // 这个函数有锁死风险
- if true {
- return false
- }
- if t.tableSink.IsDual() {
- for i := 0; i < 3; i += 2 {
- if t.users[i] == -1 {
- return false
- }
- usr := gate.GetUserInfo(t.users[i])
- if usr == nil {
- t.users[i] = -1
- return false
- }
- if usr.IsRobot() {
- t.RemoveUser(t.users[i], false, false)
- return true
- }
- }
- return false
- }
- for i := 0; i < t.chairCount; i++ {
- if t.users[i] == -1 {
- return false
- }
- usr := gate.GetUserInfo(t.users[i])
- if usr == nil {
- t.users[i] = -1
- return false
- }
- if usr.IsRobot() {
- t.RemoveUser(t.users[i], false, false)
- return true
- }
- }
- return false
- }
- func (t *ThreadsafeTable) adjustPrivateChairId(chairId int) int {
- if !t.isPrivate() {
- return chairId
- }
- if t.tableSink.OnGetChairCount() == 4 && t.tableSink.IsDual() && chairId == 1 {
- return 2
- }
- return chairId
- }
|