divwar.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package divwar
  2. import (
  3. "fmt"
  4. // "log"
  5. "net/http"
  6. "strings"
  7. "sync"
  8. "time"
  9. "wartank/pkg/components/section"
  10. "wartank/pkg/types"
  11. "wartank/server/serv_bots/warbot/angar/division/divwar/divwarnet"
  12. "wartank/server/serv_bots/warbot/angar/division/divwar/divwaron"
  13. "wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/divwarsound"
  14. "wartank/server/serv_bots/warbot/tank/tankstat/static_param"
  15. )
  16. /*
  17. Объект ожидания битвы дивизий
  18. */
  19. // DivWar -- объект ожидания битвы дивизий
  20. type DivWar struct {
  21. *section.Section
  22. bot types.IBot
  23. alarm types.IStatParam
  24. net *divwarnet.DivWarNet
  25. conn *http.Client
  26. // Непосредственная битва
  27. divon *divwaron.DivWarOn
  28. login string // Для несоредственной битвы дивизий
  29. block sync.Mutex
  30. chDivWar chan int // Сигнал начала битвы дивизий
  31. sound *divwarsound.DivWarSound // Однопоточное проигрывание звука
  32. }
  33. // NewDivWar -- возвращает новый *DivWar
  34. func NewDivWar(bot types.IBot) (*DivWar, error) {
  35. if bot == nil {
  36. return nil, fmt.Errorf("NewDivWar(): IBot == nil")
  37. }
  38. sf := &DivWar{
  39. bot: bot,
  40. alarm: static_param.NewStaticParam("alarm"),
  41. chDivWar: make(chan int, 1),
  42. sound: divwarsound.NewDivWarSound(),
  43. conn: bot.BotNet().Conn(),
  44. login: "prospero tank",
  45. }
  46. // sf.shotTimeFull.Set(8000) // 8000 msec
  47. var err error
  48. { // ISection
  49. sf.Section, err = section.NewSection(bot, "Битва дивизий", `<span>до начала `)
  50. if err != nil {
  51. return nil, fmt.Errorf("NewDivWar(): in create *Section, err=\n\t%w", err)
  52. }
  53. }
  54. { // Net
  55. sf.net, err = divwarnet.NewDivWarNet(bot)
  56. if err != nil {
  57. return nil, fmt.Errorf("NewDivWar(): при создании DivWarNet, err=\n\t%w", err)
  58. }
  59. }
  60. go sf.run()
  61. go sf.reservTick()
  62. return sf, nil
  63. }
  64. func (sf *DivWar) reservTick() {
  65. defer sf.CountDown().Stop()
  66. for {
  67. select {
  68. case <-sf.bot.Ctx().Done():
  69. return
  70. default:
  71. ct0 := sf.CountDown().Get()
  72. time.Sleep(time.Second * 7)
  73. ct1 := sf.CountDown().Get()
  74. if ct1 != ct0 {
  75. continue
  76. }
  77. if sf.divon != nil {
  78. continue
  79. }
  80. sf.chDivWar <- 1
  81. }
  82. }
  83. }
  84. // запускает в работу битву дивизий
  85. func (sf *DivWar) run() {
  86. sf.chDivWar <- 1
  87. for {
  88. select {
  89. case <-sf.bot.Ctx().Done():
  90. sf.CountDown().Stop()
  91. return
  92. case <-sf.CountDown().ChanSig(): // Время обновить данные по сражению
  93. sf.findTimeCount()
  94. sf.upDivWar()
  95. case <-sf.chDivWar: // Сигнал к началу сражения
  96. sf.block.Lock()
  97. if sf.divon != nil {
  98. continue
  99. }
  100. sf.alarm.SetVal(1)
  101. sf.sound.Play()
  102. go sf.DivWar() // Запустить цикл непосредственного сражения
  103. time.Sleep(time.Second * 10) // Задержка для звука на странице
  104. sf.alarm.SetVal(0)
  105. }
  106. }
  107. }
  108. // Ищет время до начала битвы дивизий
  109. func (sf *DivWar) findTimeCount() {
  110. if err := sf.net.UpdateLst(); err != nil { // Здесь может уже обратный отсчёт перед сражением
  111. sf.chDivWar <- 1
  112. return
  113. }
  114. var (
  115. strOut string
  116. lstDivWar = sf.GetLst()
  117. isFind bool
  118. ind int
  119. )
  120. for ind, strOut = range lstDivWar {
  121. if strings.Contains(strOut, `до начала: `) {
  122. ind++
  123. strOut = lstDivWar[ind]
  124. isFind = true
  125. break
  126. }
  127. if strings.Contains(strOut, `>ОБЫЧНЫЕ<`) { // Это уже битва
  128. sf.chDivWar <- 1
  129. return
  130. }
  131. }
  132. if !isFind { // Битва дивизий уже идёт
  133. sf.chDivWar <- 1
  134. return
  135. }
  136. lstTime := strings.Split(strOut, `<span>`)
  137. strTime := lstTime[1]
  138. lstTime = strings.Split(strTime, `</span>`)
  139. strTime = lstTime[0]
  140. if err := sf.ParseCountDown(strTime); err != nil {
  141. // log._rintf("WARN DivWar.findTimeCount(): при установке времени ожидания битвы дивизий(%v)\n\terr=%v\n", strTime, err)
  142. return
  143. }
  144. }
  145. // При необходимости поднимает взвод в атаку, вызывается только если обнаружено приглашение (+)
  146. func (sf *DivWar) upDivWar() {
  147. var (
  148. strOut string
  149. lstDivWar = sf.GetLst()
  150. isFind bool
  151. )
  152. for _, strOut = range lstDivWar {
  153. if strings.Contains(strOut, `>Взвод, подъем! В атаку!<`) {
  154. isFind = true
  155. break
  156. }
  157. if strings.Contains(strOut, `<div class="white medium cntr bold mb5">Вы в рядах участников</div>`) {
  158. // log._rintf("INFO DivWar.upDivWar(): уже зарегистрирован\n")
  159. return
  160. }
  161. }
  162. if !isFind {
  163. return
  164. }
  165. // Найдено приглашение на участие
  166. lstUp := strings.Split(strOut, `<a class="simple-but border" href="`)
  167. linkUp := lstUp[1]
  168. lstUp = strings.Split(linkUp, `"><span><span>Взвод, подъем! В атаку!</span></span></a>`)
  169. linkUp = "http://wartank.ru/" + lstUp[0]
  170. lstDivWar, err := sf.net.Get(linkUp)
  171. if err != nil {
  172. // log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
  173. return
  174. }
  175. if err = sf.Update(lstDivWar); err != nil {
  176. // log._rintf("ERRO DivWar.upDivWar(): при обновлении lstDivWar, err=\n\t%v\n", err)
  177. }
  178. // log._rintf("INFO DivWar.upDivWar(): регистрация прошла успешно\n")
  179. }
  180. // Ведёт сражение
  181. func (sf *DivWar) DivWar() {
  182. defer func() {
  183. sf.divon = nil
  184. sf.block.Unlock()
  185. if err := sf.SetCountDown(1); err != nil {
  186. panic(fmt.Errorf("DivWar.DivWar(): при установке CountDown, err=\n\t%w", err))
  187. }
  188. // log.Printf("INFO DivWar.DivWar(): сражение завершено\n")
  189. }()
  190. var err error
  191. sf.divon, err = divwaron.NewDivWarOn(sf.bot) // IDivWarOn (онлайн)
  192. if err != nil {
  193. // log._rintf("ERRO DivWar.DivWarOn(): при создании IDivWarOn, err=\n\t%v\n", err)
  194. time.Sleep(time.Millisecond * 250)
  195. return
  196. }
  197. // Цикл ожидания окончания сражения
  198. for !sf.divon.IsEnd().Get() {
  199. time.Sleep(time.Second * 1)
  200. }
  201. }
  202. // Alarm -- возвращает признак начала сражения (для браузера)
  203. func (sf *DivWar) Alarm() types.IStatParam {
  204. return sf.alarm
  205. }