tablesink.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. package gamelogic
  2. import (
  3. "encoding/json"
  4. "time"
  5. "bet24.com/log"
  6. "bet24.com/redis"
  7. "bet24.com/servers/games/fish/bullet"
  8. "bet24.com/servers/games/fish/config"
  9. "bet24.com/servers/games/fish/fish"
  10. "bet24.com/servers/games/fish/fishcommon"
  11. "bet24.com/servers/games/fish/prizepool"
  12. "bet24.com/servers/insecureframe/frame"
  13. item "bet24.com/servers/micros/item_inventory/proto"
  14. waterpool "bet24.com/servers/micros/waterpool/proto"
  15. "bet24.com/servers/user"
  16. )
  17. const room_seconds = 300
  18. type effecting struct {
  19. startTime int
  20. effectType int
  21. endTime int
  22. }
  23. func (e *effecting) expired() bool {
  24. if e.endTime == 0 {
  25. return false
  26. }
  27. return int(time.Now().Unix()) > e.endTime
  28. }
  29. type tablesink struct {
  30. table frame.Table
  31. privateData string
  32. roomInfo config.RoomInfo
  33. Users []*fishuser // 每个位置上的玩家
  34. fishmgr *fish_manager
  35. bulletmgr *bullet_manager
  36. stopped bool // 当人员离开后,下次定时器处理则可以停了
  37. groupState bool //是否鱼群来了
  38. recordmgr *RecordManager
  39. fishGroup *fish.FishGroup
  40. fishDrop *room_fish_drop
  41. groupTime int
  42. endTime int
  43. systemOdds int
  44. firstFishLog bool
  45. effecting []*effecting // 全局效果中
  46. prizePool *prizepool.PrizePool
  47. broadcastPoolValue bool
  48. newbieExtra *newbie_extra
  49. }
  50. func newTableSink(table frame.Table, data string) *tablesink {
  51. ts := new(tablesink)
  52. ts.table = table
  53. ts.privateData = data
  54. err := json.Unmarshal([]byte(data), &ts.roomInfo)
  55. if err != nil {
  56. found := false
  57. for _, v := range config.Rooms.Rooms {
  58. if data == v.RoomName {
  59. ts.roomInfo = v
  60. found = true
  61. break
  62. }
  63. }
  64. if !found {
  65. ts.roomInfo = config.Rooms.Rooms[0]
  66. }
  67. }
  68. ts.Users = make([]*fishuser, fishcommon.SEAT_COUNT)
  69. ts.fishmgr = newFishManager(ts.roomInfo.RoomName)
  70. ts.bulletmgr = newBulletManager()
  71. ts.fishDrop = newRoomFishDrop(ts.roomInfo.RoomName)
  72. ts.groupState = false
  73. ts.prizePool = prizepool.GetPrizePool(ts.roomInfo.RoomName, ts.roomInfo.BulletMin)
  74. ts.broadcastPoolValue = true
  75. ts.newbieExtra = newNewbieExtra(ts.roomInfo.RoomName)
  76. ts.table.SetTimer(fishcommon.TIMER_WRITESCORE, fishcommon.TIME_WRITESCORE)
  77. ts.table.SetTimer(fishcommon.TIMER_UPDATAWATERPOOL, fishcommon.TIME_UPDATAWATERPOOL)
  78. ts.start(true)
  79. return ts
  80. }
  81. func (ts *tablesink) start(byCreate bool) {
  82. ts.table.LogWithTableId("tablesink.start %d", ts.table.GetTableID())
  83. ts.fishmgr.clear(byCreate)
  84. ts.systemOdds = redis.String_GetInt("fish:sysodds")
  85. ts.table.LogWithTableId("tablesink.start systemOdds = %d", ts.systemOdds)
  86. ts.groupState = false
  87. ts.stopped = false
  88. ts.recordmgr = newRecordManager(ts.roomInfo.RoomName, ts.table.GetTableID(), ts.table)
  89. ts.fishGroup = fish.NewFishGroup(ts.roomInfo.GetGroup())
  90. totalSec := room_seconds
  91. if ts.roomInfo.RoomSecond > 0 {
  92. totalSec = ts.roomInfo.RoomSecond
  93. }
  94. ts.firstFishLog = true
  95. ts.effecting = nil
  96. for i := 0; i < fishcommon.SEAT_COUNT; i++ {
  97. if ts.Users[i] == nil {
  98. continue
  99. }
  100. ts.Users[i].clearSpecial()
  101. }
  102. startTime := int(time.Now().Unix())
  103. if byCreate {
  104. startTime -= fishcommon.CREATE_FORWARD_SECONDES
  105. }
  106. ts.broadcastScene()
  107. ts.endTime = startTime + totalSec
  108. if ts.fishGroup != nil {
  109. // time.AfterFunc(time.Duration(totalSec*1000-ts.fishGroup.Duration)*time.Millisecond, ts.groupCome)
  110. ts.groupTime = ts.endTime - ts.fishGroup.Duration/1000
  111. } else {
  112. ts.groupTime = 9999999999
  113. }
  114. ts.table.LogWithTableId("tablesink.start() now = %d,startTime = %d,groupTime = %d", time.Now().Unix(), startTime, ts.groupTime)
  115. // 启动定时器,产生鱼群
  116. ts.loop100ms()
  117. ts.loop1s()
  118. ts.loop5s()
  119. //time.AfterFunc(time.Duration(totalSec)*time.Second, ts.end)
  120. ts.table.StartGame()
  121. }
  122. func (ts *tablesink) groupCome() {
  123. if ts.fishGroup == nil {
  124. return
  125. }
  126. ts.table.LogWithTableId("tablesink.groupCome fishKey = %d", ts.fishmgr.fishkey)
  127. ts.fishGroup.FishKey = ts.fishmgr.fishkey
  128. ts.groupState = true
  129. ts.groupTime = int(time.Now().Unix())
  130. // 产生鱼群并下发
  131. for _, v := range ts.fishGroup.Fishes {
  132. for i := 0; i < v.Count; i++ {
  133. ts.fishmgr.addFish(v.FishID, i*v.Delay+v.GroupDelay)
  134. }
  135. }
  136. ts.sendGroup(-1, true)
  137. }
  138. func (ts *tablesink) end() {
  139. ts.table.LogWithTableId("tablesink.end")
  140. if ts.clearEffecting() {
  141. ts.broadcastEffecting()
  142. }
  143. ts.stopped = true
  144. // 清理数据
  145. // ...
  146. if ts.roomInfo.Demo == 0 {
  147. ts.recordmgr.dumpRecord()
  148. ts.recordmgr.flush()
  149. }
  150. // 如果还有人
  151. userCount := 0
  152. for i := 0; i < fishcommon.SEAT_COUNT; i++ {
  153. if ts.Users[i] == nil {
  154. continue
  155. }
  156. if ts.table.GetPlayerByUserId(ts.Users[i].userId) == nil {
  157. ts.Users[i] = nil
  158. continue
  159. }
  160. userCount++
  161. }
  162. ts.table.EndGame()
  163. if userCount > 0 {
  164. time.AfterFunc(2*time.Second, func() {
  165. ts.start(false)
  166. })
  167. } else {
  168. ts.table.CloseTable()
  169. }
  170. }
  171. // 主循环
  172. func (ts *tablesink) loop100ms() {
  173. if ts.stopped {
  174. ts.table.LogWithTableId("tablesink.loop100ms stopping %d", ts.table.GetTableID())
  175. return
  176. }
  177. // 如果鱼群来了,则不产生鱼了
  178. ts.checkFish()
  179. time.AfterFunc(100*time.Millisecond, ts.loop100ms)
  180. }
  181. func (ts *tablesink) loop1s() {
  182. if ts.stopped {
  183. ts.table.LogWithTableId("tablesink.loop1s stopping %d", ts.table.GetTableID())
  184. return
  185. }
  186. now := int(time.Now().Unix())
  187. if now >= ts.endTime {
  188. ts.end()
  189. return
  190. }
  191. if now >= ts.groupTime && !ts.groupState {
  192. ts.groupCome()
  193. }
  194. time.AfterFunc(time.Second, ts.loop1s)
  195. if ts.checkEffecting() {
  196. ts.broadcastEffecting()
  197. }
  198. if ts.broadcastPoolValue {
  199. ts.broadcastPoolValue = false
  200. ts.broadcastPool()
  201. }
  202. }
  203. func (ts *tablesink) loop5s() {
  204. if ts.stopped {
  205. ts.table.LogWithTableId("tablesink.loop5s stopping %d", ts.table.GetTableID())
  206. return
  207. }
  208. // 如果鱼群来了,则不产生鱼了
  209. time.AfterFunc(5*time.Second, ts.loop5s)
  210. ts.checkIdle()
  211. }
  212. func (ts *tablesink) Destroy() {
  213. ts.table.LogWithTableId("------tablesink:Destroy-------")
  214. //close(ts.stopChan)
  215. }
  216. func (ts *tablesink) OnUserEnterTable(userIndex int32, chairId int) {
  217. u, _ := ts.table.GetUser(userIndex)
  218. if u == nil {
  219. ts.table.LogWithTableId("tablesink.OnUserEnterTable %d not exist", userIndex)
  220. return
  221. }
  222. ts.newbieExtra.onUserEnter(u.GetUserId())
  223. ts.Users[chairId] = newFishUser(u.GetUserId(), ts.roomInfo.BulletMin, ts.roomInfo.BulletMax, ts.newbieExtra)
  224. ts.sendConfig(userIndex)
  225. // 处理炮台相关
  226. // ...
  227. ts.broadCastUserInfo(u)
  228. gameScene := ts.getChairScene()
  229. ts.table.SendGameData(userIndex, fishcommon.GAME_SCENE, gameScene)
  230. // 如果鱼群来了
  231. if ts.groupState {
  232. ts.sendGroup(userIndex, false)
  233. }
  234. }
  235. func (ts *tablesink) OnUserExitTable(userIndex int32, chairId int) {
  236. u, _ := ts.table.GetUser(userIndex)
  237. if u == nil {
  238. ts.table.LogWithTableId("tablesink.OnUserExitTable %d not exist", userIndex)
  239. return
  240. }
  241. fUser := ts.getRoomUser(u.GetUserId())
  242. if fUser != nil {
  243. ts.doWriteUserGold(fUser)
  244. value, bet := fUser.getWaterPoolValueAndClear()
  245. if fUser.isInControl() {
  246. go waterpool.UpdataUserWaterPool(u.GetUserId(), value, fishcommon.GAME_NAME, waterpool.RoomType_Normal, ts.roomInfo.RoomID)
  247. } else {
  248. go waterpool.AddBet(u.GetUserGold(), bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName)
  249. go waterpool.ReducePool(u.GetUserGold(), value+bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName)
  250. }
  251. }
  252. ts.newbieExtra.onUserExit(u.GetUserId())
  253. ts.Users[chairId] = nil
  254. }
  255. func (ts *tablesink) OnUserOffline(chairId int) {
  256. }
  257. func (ts *tablesink) OnUserReplay(chairId int) {
  258. }
  259. func (ts *tablesink) OnUserReady(userIndex int32, chairId int) {
  260. }
  261. func (ts *tablesink) OnUserCancelReady(userIndex int32, chairId int) {
  262. }
  263. func (ts *tablesink) getChairScene() string {
  264. var gameScene fishcommon.GameScene
  265. gameScene.RoomID = ts.table.GetTableID()
  266. gameScene.BossAfter = ts.getBossAfter()
  267. gameScene.Effecting = ts.getEffecting()
  268. // user
  269. gameScene.Users = make([]fishcommon.GameScene_User, fishcommon.SEAT_COUNT)
  270. for i := 0; i < fishcommon.SEAT_COUNT; i++ {
  271. if ts.Users[i] == nil {
  272. gameScene.Users[i].UserId = -1
  273. } else {
  274. gameScene.Users[i].UserId = ts.Users[i].userId
  275. gameScene.Users[i].CannonId = ts.Users[i].CannonId
  276. gameScene.Users[i].Bullet = ts.Users[i].BulletId
  277. }
  278. }
  279. // fish
  280. if !ts.groupState {
  281. gameScene.Fishes = ts.fishmgr.fish_list
  282. for _, v := range gameScene.Fishes {
  283. v.Age = v.GetAge()
  284. }
  285. }
  286. d, _ := json.Marshal(gameScene)
  287. return string(d)
  288. }
  289. func (ts *tablesink) OnGetChairScene(chairId int, isPlayer bool) string {
  290. return ""
  291. }
  292. func (ts *tablesink) OnGetPrivateRoomScene(chairId int) string {
  293. return ts.OnGetChairScene(chairId, true)
  294. }
  295. func (ts *tablesink) OnGetChairCount() int {
  296. return fishcommon.SEAT_COUNT
  297. }
  298. func (ts *tablesink) OnTimer(timerId int) {
  299. switch timerId {
  300. case fishcommon.TIMER_WRITESCORE:
  301. ts.onTimerWriteScore()
  302. case fishcommon.TIMER_UPDATAWATERPOOL:
  303. ts.updataUserExtraOdds()
  304. default:
  305. ts.table.LogWithTableId("tablesink.OnTimer unhandled timer[%d]", timerId)
  306. }
  307. }
  308. func (ts *tablesink) DumpScene() {
  309. log.Release(ts.getChairScene())
  310. }
  311. func (ts *tablesink) GetGoldLimit() (min, max int) {
  312. return ts.roomInfo.RoomMin, ts.roomInfo.RoomMax
  313. }
  314. func (ts *tablesink) IsDual() bool {
  315. return false
  316. }
  317. func (ts *tablesink) OnBaseScoreChanged(baseScore int) {
  318. }
  319. func (ts *tablesink) SetPrivateRoomParam(param int, value string) {
  320. ts.table.LogWithTableId("tablesink.SetPrivateRoomParam %d:%s", param, value)
  321. }
  322. func (ts *tablesink) OnPrivateRoomStatusChanged(oldStatus, newStatus int) {
  323. ts.table.LogWithTableId("OnPrivateRoomStatusChanged %d->%d", oldStatus, newStatus)
  324. }
  325. func (ts *tablesink) OnPrivateRoomDismissed() {
  326. ts.table.LogWithTableId("OnPrivateRoomDismissed ")
  327. }
  328. func (ts *tablesink) getBossAfter() int {
  329. return ts.fishmgr.getBossAfter()
  330. }
  331. func (ts *tablesink) getEffecting() []int {
  332. var ret []int
  333. for _, v := range ts.effecting {
  334. ret = append(ret, v.effectType)
  335. }
  336. return ret
  337. }
  338. func (ts *tablesink) broadCastUserInfo(usr *user.UserInfo) {
  339. msg := fishcommon.UPDATE_USER_INFO
  340. userInfo := ts.getRoomUser(usr.GetUserId())
  341. if userInfo == nil {
  342. return
  343. }
  344. var data fishcommon.UpdateUserInfo
  345. data.UserId = usr.GetUserId()
  346. data.Gold = usr.GetUserGold()
  347. data.BulletID = userInfo.BulletId
  348. data.Cannon = userInfo.CannonId
  349. data.Essence = userInfo.Essence
  350. d, _ := json.Marshal(data)
  351. ts.broadcastData(msg, string(d))
  352. }
  353. func (ts *tablesink) broadCastUseItem(useItem fishcommon.UseItem) {
  354. msg := fishcommon.USE_ITEM
  355. d, _ := json.Marshal(useItem)
  356. ts.broadcastData(msg, string(d))
  357. }
  358. func (ts *tablesink) sendGroup(userIndex int32, locked bool) {
  359. msg := fishcommon.GROUP_COME
  360. now := int(time.Now().Unix())
  361. passMs := (now - ts.groupTime) * 1000
  362. for i := 0; i < len(ts.effecting); i++ {
  363. if ts.effecting[i].effectType == item.SpecialEffect_Frozen {
  364. passMs = (ts.effecting[i].startTime - ts.groupTime) * 1000
  365. }
  366. }
  367. data := ts.fishGroup.GetJson(passMs)
  368. ts.table.SendGameData(userIndex, msg, data)
  369. }
  370. func (ts *tablesink) BroadcastUserInfo(userID int) {
  371. usr := ts.table.GetPlayerByUserId(userID)
  372. if usr != nil {
  373. ts.broadCastUserInfo(usr)
  374. }
  375. }
  376. func (ts *tablesink) broadcastScene() {
  377. msg := fishcommon.GAME_SCENE
  378. gameScene := ts.getChairScene()
  379. ts.broadcastData(msg, gameScene)
  380. }
  381. func (ts *tablesink) broadcastEffecting() {
  382. msg := fishcommon.EFFECTING
  383. d, _ := json.Marshal(ts.getEffecting())
  384. ts.broadcastData(msg, string(d))
  385. }
  386. func (ts *tablesink) isFrozening() bool {
  387. for i := 0; i < len(ts.effecting); i++ {
  388. if ts.effecting[i].effectType == item.SpecialEffect_Frozen {
  389. return true
  390. }
  391. }
  392. return false
  393. }
  394. func (ts *tablesink) addEffecting(effectType int, duration int) {
  395. if duration == 0 {
  396. return
  397. }
  398. now := int(time.Now().Unix())
  399. deltaTime := duration
  400. defer func(dt int) {
  401. if effectType == item.SpecialEffect_Frozen && !ts.groupState {
  402. ts.groupTime += dt
  403. ts.endTime += dt
  404. ts.fishmgr.pauseForFrozen(int64(dt))
  405. }
  406. ts.broadcastEffecting()
  407. }(deltaTime)
  408. for _, v := range ts.effecting {
  409. if v.effectType == effectType {
  410. deltaTime = duration - (v.endTime - now)
  411. v.endTime = now + duration
  412. return
  413. }
  414. }
  415. ts.effecting = append(ts.effecting, &effecting{effectType: effectType, startTime: now, endTime: now + duration})
  416. }
  417. func (ts *tablesink) checkEffecting() bool {
  418. ret := false
  419. for i := 0; i < len(ts.effecting); i++ {
  420. if ts.effecting[i].expired() {
  421. ts.effecting = append(ts.effecting[:i], ts.effecting[i+1:]...)
  422. ret = true
  423. }
  424. }
  425. return ret
  426. }
  427. func (ts *tablesink) clearEffecting() bool {
  428. if len(ts.effecting) > 0 {
  429. ts.effecting = nil
  430. return true
  431. } else {
  432. return false
  433. }
  434. }
  435. func (ts *tablesink) sendPoolEnergy(userId int) {
  436. if ts.prizePool == nil {
  437. return
  438. }
  439. u := ts.table.GetPlayerByUserId(userId)
  440. if u == nil {
  441. return
  442. }
  443. var poolEnergy struct {
  444. Energy int
  445. FullEnergy int
  446. }
  447. poolEnergy.Energy = ts.prizePool.GetUserEnergy(userId)
  448. poolEnergy.FullEnergy = ts.prizePool.FullEnergy
  449. d, _ := json.Marshal(poolEnergy)
  450. go ts.table.SendGameData(u.GetUserIndex(), fishcommon.POOL_ENERGY, string(d))
  451. }
  452. func (ts *tablesink) checkFish() {
  453. // 如果当前处于冰冻期,则不检查生成
  454. if ts.isFrozening() {
  455. return
  456. }
  457. fishes := ts.fishmgr.generateFish(ts.groupState)
  458. for _, fish := range fishes {
  459. if ts.firstFishLog {
  460. ts.firstFishLog = false
  461. ts.table.LogWithTableId("first fish generateFish %d", fish.FishID)
  462. }
  463. fish.Age = fish.GetAge()
  464. msg := fishcommon.ADD_FISH
  465. d, _ := json.Marshal(fish)
  466. data := string(d)
  467. ts.broadcastData(msg, data)
  468. }
  469. }
  470. func (ts *tablesink) checkIdle() {
  471. var idleUserIds []int
  472. for i := 0; i < fishcommon.SEAT_COUNT; i++ {
  473. if ts.Users[i] == nil {
  474. continue
  475. }
  476. if ts.Users[i].isIdled() {
  477. idleUserIds = append(idleUserIds, i)
  478. }
  479. }
  480. for _, v := range idleUserIds {
  481. ts.table.LogWithTableId("tablesink.checkIdle removing user chair[%d]", v)
  482. ts.table.KickUserByChair(v, true)
  483. }
  484. }
  485. // 额外概率后续根据需求做修改,先给一个值做测试
  486. func (ts *tablesink) updataUserExtraOdds() {
  487. ts.table.SetTimer(fishcommon.TIMER_UPDATAWATERPOOL, fishcommon.TIME_UPDATAWATERPOOL)
  488. go ts.doUpdateUserExtraOddsOdds()
  489. }
  490. func (ts *tablesink) doUpdateUserExtraOddsOdds() {
  491. for i := 0; i < fishcommon.SEAT_COUNT; i++ {
  492. if ts.Users[i] == nil {
  493. continue
  494. }
  495. u := ts.table.GetUserByUserId(ts.Users[i].userId)
  496. if u == nil {
  497. continue
  498. }
  499. bulletInfo := bullet.GetBullet(ts.Users[i].getBulletId())
  500. if bulletInfo == nil {
  501. ts.table.LogWithTableId("bulletInfo is nil")
  502. continue
  503. }
  504. value, bet := ts.Users[i].getWaterPoolValueAndClear()
  505. if ts.Users[i].isInControl() {
  506. waterpool.UpdataUserWaterPool(u.GetUserId(), value, fishcommon.GAME_NAME, waterpool.RoomType_Normal, ts.roomInfo.RoomID)
  507. } else {
  508. waterpool.AddBet(u.GetUserGold(), bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName)
  509. waterpool.ReducePool(u.GetUserGold(), value+bet, false, fishcommon.GAMEID, ts.roomInfo.RoomName)
  510. }
  511. poolType, usrOdds := waterpool.GetUserPoolType(u.GetUserId(), fishcommon.GAMEID, waterpool.GameType_Normal, ts.roomInfo.RoomMin,
  512. u.GetUserGold(), false, bulletInfo.Odds)
  513. ts.table.LogWithTableId("userId:%d, poolType:%d, userodds:%d", u.GetUserId(), poolType, usrOdds)
  514. if poolType != waterpool.PoolControl_Normal {
  515. ts.Users[i].setUserExtraOdd(usrOdds, true)
  516. } else {
  517. waterType, sysOdds := waterpool.GetControlProb(u.GetUserGold(), false, fishcommon.GAMEID, ts.roomInfo.RoomName)
  518. ts.table.LogWithTableId("userId:%d, waterType:%d, sysodds:%d", u.GetUserId(), waterType, sysOdds)
  519. if waterType == waterpool.PoolControl_Normal {
  520. ts.Users[i].setUserExtraOdd(0, false)
  521. } else {
  522. ts.Users[i].setUserExtraOdd(sysOdds, false)
  523. }
  524. }
  525. }
  526. }
  527. func (ts *tablesink) IsAllRobot() bool {
  528. return false
  529. }