package gamelogic import ( "encoding/json" "time" "bet24.com/log" "bet24.com/redis" "bet24.com/servers/games/fish/bullet" "bet24.com/servers/games/fish/config" "bet24.com/servers/games/fish/fish" "bet24.com/servers/games/fish/fishcommon" "bet24.com/servers/games/fish/prizepool" "bet24.com/servers/insecureframe/frame" item "bet24.com/servers/micros/item_inventory/proto" waterpool "bet24.com/servers/micros/waterpool/proto" "bet24.com/servers/user" ) const room_seconds = 300 type effecting struct { startTime int effectType int endTime int } func (e *effecting) expired() bool { if e.endTime == 0 { return false } return int(time.Now().Unix()) > e.endTime } type tablesink struct { table frame.Table privateData string roomInfo config.RoomInfo Users []*fishuser // 每个位置上的玩家 fishmgr *fish_manager bulletmgr *bullet_manager stopped bool // 当人员离开后,下次定时器处理则可以停了 groupState bool //是否鱼群来了 recordmgr *RecordManager fishGroup *fish.FishGroup fishDrop *room_fish_drop groupTime int endTime int systemOdds int firstFishLog bool effecting []*effecting // 全局效果中 prizePool *prizepool.PrizePool broadcastPoolValue bool newbieExtra *newbie_extra } func newTableSink(table frame.Table, data string) *tablesink { ts := new(tablesink) ts.table = table ts.privateData = data err := json.Unmarshal([]byte(data), &ts.roomInfo) if err != nil { found := false for _, v := range config.Rooms.Rooms { if data == v.RoomName { ts.roomInfo = v found = true break } } if !found { ts.roomInfo = config.Rooms.Rooms[0] } } ts.Users = make([]*fishuser, fishcommon.SEAT_COUNT) ts.fishmgr = newFishManager(ts.roomInfo.RoomName) ts.bulletmgr = newBulletManager() ts.fishDrop = newRoomFishDrop(ts.roomInfo.RoomName) ts.groupState = false ts.prizePool = prizepool.GetPrizePool(ts.roomInfo.RoomName, ts.roomInfo.BulletMin) ts.broadcastPoolValue = true ts.newbieExtra = newNewbieExtra(ts.roomInfo.RoomName) ts.table.SetTimer(fishcommon.TIMER_WRITESCORE, fishcommon.TIME_WRITESCORE) ts.table.SetTimer(fishcommon.TIMER_UPDATAWATERPOOL, fishcommon.TIME_UPDATAWATERPOOL) ts.start(true) return ts } func (ts *tablesink) start(byCreate bool) { ts.table.LogWithTableId("tablesink.start %d", ts.table.GetTableID()) ts.fishmgr.clear(byCreate) ts.systemOdds = redis.String_GetInt("fish:sysodds") ts.table.LogWithTableId("tablesink.start systemOdds = %d", ts.systemOdds) ts.groupState = false ts.stopped = false ts.recordmgr = newRecordManager(ts.roomInfo.RoomName, ts.table.GetTableID(), ts.table) ts.fishGroup = fish.NewFishGroup(ts.roomInfo.GetGroup()) totalSec := room_seconds if ts.roomInfo.RoomSecond > 0 { totalSec = ts.roomInfo.RoomSecond } ts.firstFishLog = true ts.effecting = nil for i := 0; i < fishcommon.SEAT_COUNT; i++ { if ts.Users[i] == nil { continue } ts.Users[i].clearSpecial() } startTime := int(time.Now().Unix()) if byCreate { startTime -= fishcommon.CREATE_FORWARD_SECONDES } ts.broadcastScene() ts.endTime = startTime + totalSec if ts.fishGroup != nil { // time.AfterFunc(time.Duration(totalSec*1000-ts.fishGroup.Duration)*time.Millisecond, ts.groupCome) ts.groupTime = ts.endTime - ts.fishGroup.Duration/1000 } else { ts.groupTime = 9999999999 } ts.table.LogWithTableId("tablesink.start() now = %d,startTime = %d,groupTime = %d", time.Now().Unix(), startTime, ts.groupTime) // 启动定时器,产生鱼群 ts.loop100ms() ts.loop1s() ts.loop5s() //time.AfterFunc(time.Duration(totalSec)*time.Second, ts.end) ts.table.StartGame() } func (ts *tablesink) groupCome() { if ts.fishGroup == nil { return } ts.table.LogWithTableId("tablesink.groupCome fishKey = %d", ts.fishmgr.fishkey) ts.fishGroup.FishKey = ts.fishmgr.fishkey ts.groupState = true ts.groupTime = int(time.Now().Unix()) // 产生鱼群并下发 for _, v := range ts.fishGroup.Fishes { for i := 0; i < v.Count; i++ { ts.fishmgr.addFish(v.FishID, i*v.Delay+v.GroupDelay) } } ts.sendGroup(-1, true) } func (ts *tablesink) end() { ts.table.LogWithTableId("tablesink.end") if ts.clearEffecting() { ts.broadcastEffecting() } ts.stopped = true // 清理数据 // ... if ts.roomInfo.Demo == 0 { ts.recordmgr.dumpRecord() ts.recordmgr.flush() } // 如果还有人 userCount := 0 for i := 0; i < fishcommon.SEAT_COUNT; i++ { if ts.Users[i] == nil { continue } if ts.table.GetPlayerByUserId(ts.Users[i].userId) == nil { ts.Users[i] = nil continue } userCount++ } ts.table.EndGame() if userCount > 0 { time.AfterFunc(2*time.Second, func() { ts.start(false) }) } else { ts.table.CloseTable() } } // 主循环 func (ts *tablesink) loop100ms() { if ts.stopped { ts.table.LogWithTableId("tablesink.loop100ms stopping %d", ts.table.GetTableID()) return } // 如果鱼群来了,则不产生鱼了 ts.checkFish() time.AfterFunc(100*time.Millisecond, ts.loop100ms) } func (ts *tablesink) loop1s() { if ts.stopped { ts.table.LogWithTableId("tablesink.loop1s stopping %d", ts.table.GetTableID()) return } now := int(time.Now().Unix()) if now >= ts.endTime { ts.end() return } if now >= ts.groupTime && !ts.groupState { ts.groupCome() } time.AfterFunc(time.Second, ts.loop1s) if ts.checkEffecting() { ts.broadcastEffecting() } if ts.broadcastPoolValue { ts.broadcastPoolValue = false ts.broadcastPool() } } func (ts *tablesink) loop5s() { if ts.stopped { ts.table.LogWithTableId("tablesink.loop5s stopping %d", ts.table.GetTableID()) return } // 如果鱼群来了,则不产生鱼了 time.AfterFunc(5*time.Second, ts.loop5s) ts.checkIdle() } func (ts *tablesink) Destroy() { ts.table.LogWithTableId("------tablesink:Destroy-------") //close(ts.stopChan) } func (ts *tablesink) OnUserEnterTable(userIndex int32, chairId int) { u, _ := ts.table.GetUser(userIndex) if u == nil { ts.table.LogWithTableId("tablesink.OnUserEnterTable %d not exist", userIndex) return } ts.newbieExtra.onUserEnter(u.GetUserId()) ts.Users[chairId] = newFishUser(u.GetUserId(), ts.roomInfo.BulletMin, ts.roomInfo.BulletMax, ts.newbieExtra) ts.sendConfig(userIndex) // 处理炮台相关 // ... ts.broadCastUserInfo(u) gameScene := ts.getChairScene() ts.table.SendGameData(userIndex, fishcommon.GAME_SCENE, gameScene) // 如果鱼群来了 if ts.groupState { ts.sendGroup(userIndex, false) } } func (ts *tablesink) OnUserExitTable(userIndex int32, chairId int) { u, _ := ts.table.GetUser(userIndex) if u == nil { ts.table.LogWithTableId("tablesink.OnUserExitTable %d not exist", userIndex) return } fUser := ts.getRoomUser(u.GetUserId()) if fUser != nil { ts.doWriteUserGold(fUser) value, bet := fUser.getWaterPoolValueAndClear() if fUser.isInControl() { go waterpool.UpdataUserWaterPool(u.GetUserId(), value, fishcommon.GAME_NAME, waterpool.RoomType_Normal, ts.roomInfo.RoomID) } else { go waterpool.AddBet(u.GetUserGold(), bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName) go waterpool.ReducePool(u.GetUserGold(), value+bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName) } } ts.newbieExtra.onUserExit(u.GetUserId()) ts.Users[chairId] = nil } func (ts *tablesink) OnUserOffline(chairId int) { } func (ts *tablesink) OnUserReplay(chairId int) { } func (ts *tablesink) OnUserReady(userIndex int32, chairId int) { } func (ts *tablesink) OnUserCancelReady(userIndex int32, chairId int) { } func (ts *tablesink) getChairScene() string { var gameScene fishcommon.GameScene gameScene.RoomID = ts.table.GetTableID() gameScene.BossAfter = ts.getBossAfter() gameScene.Effecting = ts.getEffecting() // user gameScene.Users = make([]fishcommon.GameScene_User, fishcommon.SEAT_COUNT) for i := 0; i < fishcommon.SEAT_COUNT; i++ { if ts.Users[i] == nil { gameScene.Users[i].UserId = -1 } else { gameScene.Users[i].UserId = ts.Users[i].userId gameScene.Users[i].CannonId = ts.Users[i].CannonId gameScene.Users[i].Bullet = ts.Users[i].BulletId } } // fish if !ts.groupState { gameScene.Fishes = ts.fishmgr.fish_list for _, v := range gameScene.Fishes { v.Age = v.GetAge() } } d, _ := json.Marshal(gameScene) return string(d) } func (ts *tablesink) OnGetChairScene(chairId int, isPlayer bool) string { return "" } func (ts *tablesink) OnGetPrivateRoomScene(chairId int) string { return ts.OnGetChairScene(chairId, true) } func (ts *tablesink) OnGetChairCount() int { return fishcommon.SEAT_COUNT } func (ts *tablesink) OnTimer(timerId int) { switch timerId { case fishcommon.TIMER_WRITESCORE: ts.onTimerWriteScore() case fishcommon.TIMER_UPDATAWATERPOOL: ts.updataUserExtraOdds() default: ts.table.LogWithTableId("tablesink.OnTimer unhandled timer[%d]", timerId) } } func (ts *tablesink) DumpScene() { log.Release(ts.getChairScene()) } func (ts *tablesink) GetGoldLimit() (min, max int) { return ts.roomInfo.RoomMin, ts.roomInfo.RoomMax } func (ts *tablesink) IsDual() bool { return false } func (ts *tablesink) OnBaseScoreChanged(baseScore int) { } func (ts *tablesink) SetPrivateRoomParam(param int, value string) { ts.table.LogWithTableId("tablesink.SetPrivateRoomParam %d:%s", param, value) } func (ts *tablesink) OnPrivateRoomStatusChanged(oldStatus, newStatus int) { ts.table.LogWithTableId("OnPrivateRoomStatusChanged %d->%d", oldStatus, newStatus) } func (ts *tablesink) OnPrivateRoomDismissed() { ts.table.LogWithTableId("OnPrivateRoomDismissed ") } func (ts *tablesink) getBossAfter() int { return ts.fishmgr.getBossAfter() } func (ts *tablesink) getEffecting() []int { var ret []int for _, v := range ts.effecting { ret = append(ret, v.effectType) } return ret } func (ts *tablesink) broadCastUserInfo(usr *user.UserInfo) { msg := fishcommon.UPDATE_USER_INFO userInfo := ts.getRoomUser(usr.GetUserId()) if userInfo == nil { return } var data fishcommon.UpdateUserInfo data.UserId = usr.GetUserId() data.Gold = usr.GetUserGold() data.BulletID = userInfo.BulletId data.Cannon = userInfo.CannonId data.Essence = userInfo.Essence d, _ := json.Marshal(data) ts.broadcastData(msg, string(d)) } func (ts *tablesink) broadCastUseItem(useItem fishcommon.UseItem) { msg := fishcommon.USE_ITEM d, _ := json.Marshal(useItem) ts.broadcastData(msg, string(d)) } func (ts *tablesink) sendGroup(userIndex int32, locked bool) { msg := fishcommon.GROUP_COME now := int(time.Now().Unix()) passMs := (now - ts.groupTime) * 1000 for i := 0; i < len(ts.effecting); i++ { if ts.effecting[i].effectType == item.SpecialEffect_Frozen { passMs = (ts.effecting[i].startTime - ts.groupTime) * 1000 } } data := ts.fishGroup.GetJson(passMs) ts.table.SendGameData(userIndex, msg, data) } func (ts *tablesink) BroadcastUserInfo(userID int) { usr := ts.table.GetPlayerByUserId(userID) if usr != nil { ts.broadCastUserInfo(usr) } } func (ts *tablesink) broadcastScene() { msg := fishcommon.GAME_SCENE gameScene := ts.getChairScene() ts.broadcastData(msg, gameScene) } func (ts *tablesink) broadcastEffecting() { msg := fishcommon.EFFECTING d, _ := json.Marshal(ts.getEffecting()) ts.broadcastData(msg, string(d)) } func (ts *tablesink) isFrozening() bool { for i := 0; i < len(ts.effecting); i++ { if ts.effecting[i].effectType == item.SpecialEffect_Frozen { return true } } return false } func (ts *tablesink) addEffecting(effectType int, duration int) { if duration == 0 { return } now := int(time.Now().Unix()) deltaTime := duration defer func(dt int) { if effectType == item.SpecialEffect_Frozen && !ts.groupState { ts.groupTime += dt ts.endTime += dt ts.fishmgr.pauseForFrozen(int64(dt)) } ts.broadcastEffecting() }(deltaTime) for _, v := range ts.effecting { if v.effectType == effectType { deltaTime = duration - (v.endTime - now) v.endTime = now + duration return } } ts.effecting = append(ts.effecting, &effecting{effectType: effectType, startTime: now, endTime: now + duration}) } func (ts *tablesink) checkEffecting() bool { ret := false for i := 0; i < len(ts.effecting); i++ { if ts.effecting[i].expired() { ts.effecting = append(ts.effecting[:i], ts.effecting[i+1:]...) ret = true } } return ret } func (ts *tablesink) clearEffecting() bool { if len(ts.effecting) > 0 { ts.effecting = nil return true } else { return false } } func (ts *tablesink) sendPoolEnergy(userId int) { if ts.prizePool == nil { return } u := ts.table.GetPlayerByUserId(userId) if u == nil { return } var poolEnergy struct { Energy int FullEnergy int } poolEnergy.Energy = ts.prizePool.GetUserEnergy(userId) poolEnergy.FullEnergy = ts.prizePool.FullEnergy d, _ := json.Marshal(poolEnergy) go ts.table.SendGameData(u.GetUserIndex(), fishcommon.POOL_ENERGY, string(d)) } func (ts *tablesink) checkFish() { // 如果当前处于冰冻期,则不检查生成 if ts.isFrozening() { return } fishes := ts.fishmgr.generateFish(ts.groupState) for _, fish := range fishes { if ts.firstFishLog { ts.firstFishLog = false ts.table.LogWithTableId("first fish generateFish %d", fish.FishID) } fish.Age = fish.GetAge() msg := fishcommon.ADD_FISH d, _ := json.Marshal(fish) data := string(d) ts.broadcastData(msg, data) } } func (ts *tablesink) checkIdle() { var idleUserIds []int for i := 0; i < fishcommon.SEAT_COUNT; i++ { if ts.Users[i] == nil { continue } if ts.Users[i].isIdled() { idleUserIds = append(idleUserIds, i) } } for _, v := range idleUserIds { ts.table.LogWithTableId("tablesink.checkIdle removing user chair[%d]", v) ts.table.KickUserByChair(v, true) } } // 额外概率后续根据需求做修改,先给一个值做测试 func (ts *tablesink) updataUserExtraOdds() { ts.table.SetTimer(fishcommon.TIMER_UPDATAWATERPOOL, fishcommon.TIME_UPDATAWATERPOOL) go ts.doUpdateUserExtraOddsOdds() } func (ts *tablesink) doUpdateUserExtraOddsOdds() { for i := 0; i < fishcommon.SEAT_COUNT; i++ { if ts.Users[i] == nil { continue } u := ts.table.GetUserByUserId(ts.Users[i].userId) if u == nil { continue } bulletInfo := bullet.GetBullet(ts.Users[i].getBulletId()) if bulletInfo == nil { ts.table.LogWithTableId("bulletInfo is nil") continue } value, bet := ts.Users[i].getWaterPoolValueAndClear() if ts.Users[i].isInControl() { waterpool.UpdataUserWaterPool(u.GetUserId(), value, fishcommon.GAME_NAME, waterpool.RoomType_Normal, ts.roomInfo.RoomID) } else { waterpool.AddBet(u.GetUserGold(), bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName) waterpool.ReducePool(u.GetUserGold(), value+bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName) } poolType, usrOdds := waterpool.GetUserPoolType(u.GetUserId(), fishcommon.GAMEID, waterpool.GameType_Normal, ts.roomInfo.RoomMin, u.GetUserGold(), false, bulletInfo.Odds) ts.table.LogWithTableId("userId:%d, poolType:%d, userodds:%d", u.GetUserId(), poolType, usrOdds) if poolType != waterpool.PoolControl_Normal { ts.Users[i].setUserExtraOdd(usrOdds, true) } else { waterType, sysOdds := waterpool.GetControlProb(u.GetUserGold(), false, fishcommon.GAMEID, ts.roomInfo.RoomName) ts.table.LogWithTableId("userId:%d, waterType:%d, sysodds:%d", u.GetUserId(), waterType, sysOdds) if waterType == waterpool.PoolControl_Normal { ts.Users[i].setUserExtraOdd(0, false) } else { ts.Users[i].setUserExtraOdd(sysOdds, false) } } } } func (ts *tablesink) IsAllRobot() bool { return false }