divwar.go 6.5 KB

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