service.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. package conscript
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. capp "f1-game/internal/cherry_app"
  5. "f1-game/internal/code"
  6. "f1-game/internal/constant"
  7. "f1-game/internal/data"
  8. "f1-game/internal/enum"
  9. "f1-game/internal/event"
  10. "f1-game/internal/extend/math"
  11. facade "f1-game/internal/facade"
  12. nameRoute "f1-game/internal/name/route"
  13. "f1-game/internal/sessions"
  14. ao "f1-game/nodes/game/player/asset/origin"
  15. "f1-game/nodes/map/internal/db"
  16. mapFacade "f1-game/nodes/map/internal/facade"
  17. "f1-game/nodes/map/player/storage"
  18. ctime "github.com/cherry-game/cherry/extend/time"
  19. clog "github.com/cherry-game/cherry/logger"
  20. cproto "github.com/cherry-game/cherry/net/proto"
  21. )
  22. var srv = &service{}
  23. type service struct {
  24. facade.PlayerServiceBase[*db.MapPlayerTable]
  25. }
  26. func Service() *service {
  27. return srv
  28. }
  29. func (p *service) OnLogin(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) {
  30. // 当前没有征兵/升级任务
  31. if mapPlayerTable.Conscripts.IsNotConscriptAction() {
  32. return
  33. }
  34. // 计算登录时间和登出的时间差
  35. var (
  36. nowMilliSecond = ctime.Now().ToMillisecond()
  37. lastLogoutTime = mapPlayerTable.Stats.LastLogoutTime
  38. diffSecond = (nowMilliSecond - lastLogoutTime) / ctime.MillisecondsPerSecond
  39. )
  40. // 结算离线征兵/兵种升级
  41. p.handleConscriptSettle(mapPlayerTable, int32(diffSecond))
  42. }
  43. func (p *service) OnLogout(mapPlayerTable *db.MapPlayerTable) {
  44. mapPlayerTable.Stats.LastLogoutTime = ctime.Now().ToMillisecond()
  45. mapPlayerTable.Save2Queue()
  46. }
  47. // func (p *service) OnReset(mapPlayerTable *db.PlayerTable, time *ctime.CherryTime, byLogin bool) {
  48. // }
  49. // 推送征兵信息
  50. func (p *service) Push(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) {
  51. resp := mapPlayerTable.Conscripts.ToProto()
  52. sessions.PushWithSession(session, nameRoute.PushMapPlayer_Conscript, &resp)
  53. }
  54. // 每秒执行征兵结算
  55. func (p *service) ConscriptSettle(playerID, nowSecond int64) {
  56. mapPlayerTable := db.GetMapPlayerTable(playerID)
  57. if mapPlayerTable == nil {
  58. clog.Warnf("conscript settle player not found. playerID:%d", playerID)
  59. return
  60. }
  61. // 1s 计算
  62. p.handleConscriptSettle(mapPlayerTable, 1)
  63. }
  64. func (p *service) handleConscriptSettle(mapPlayerTable *db.MapPlayerTable, second int32) {
  65. // 当前没有征兵/升级任务
  66. if mapPlayerTable.Conscripts.IsNotConscriptAction() {
  67. return
  68. }
  69. var (
  70. conscripts = mapPlayerTable.Conscripts
  71. save = false
  72. )
  73. // 当前为征兵
  74. if conscripts.IsConscript() {
  75. // 执行1s征兵结算
  76. save = p.doConscriptSettle(mapPlayerTable, second)
  77. // 如果当前征兵已完成 且 开启自动征兵 则执行下一次征兵
  78. if conscripts.Conscript.IsConscriptFinish() && conscripts.Conscript.AutoConscript {
  79. if ok := p.AutoConscript(mapPlayerTable, conscripts.Conscript.ArmID); ok {
  80. save = true
  81. }
  82. }
  83. }
  84. // 当前为士兵升级
  85. if conscripts.IsConscriptUp() {
  86. save = p.doConscriptUpSettle(mapPlayerTable, second)
  87. }
  88. // 保存征兵数据
  89. if save {
  90. mapPlayerTable.Save2Queue()
  91. // 通知客户端
  92. session, found := sessions.GetSession(mapPlayerTable.PlayerID)
  93. if found {
  94. p.Push(mapPlayerTable, session)
  95. }
  96. }
  97. }
  98. // TODO 后面改成 执行征兵结算
  99. func (p *service) doConscriptSettle(mapPlayerTable *db.MapPlayerTable, second int32) bool {
  100. var (
  101. playerID = mapPlayerTable.PlayerID
  102. armID = mapPlayerTable.Conscripts.Conscript.ArmID
  103. num = int64(mapPlayerTable.Conscripts.Conscript.ConscriptRemain())
  104. )
  105. if num <= 0 || armID <= 0 {
  106. return false
  107. }
  108. armLevelRow, found := data.ArmLevel.GetByID(armID)
  109. if !found {
  110. clog.Warnf("[doConscriptSettle] arm level config not found. armID:%d", armID)
  111. return false
  112. }
  113. var (
  114. // 预备兵上限
  115. armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit)
  116. // 获取征兵/升级的士兵当前数量
  117. curNum = p.GetCurTroopNum(playerID)
  118. )
  119. // 判断如果数量已达上限 则更新时间 不结算
  120. if curNum >= armLimit {
  121. return false
  122. }
  123. // 获得兵力= 结算次数 * 结算时间 * 单次兵力
  124. addNum := p.calConscriptNumSecond(mapPlayerTable, second*armLevelRow.ConscriptNumSecond)
  125. if addNum <= 0 {
  126. clog.Warnf("[doConscriptSettle] calConscriptNumSecond num <= 0. playerID = %d", playerID)
  127. return false
  128. }
  129. if addNum >= num {
  130. addNum = num
  131. }
  132. // 修正添加数量
  133. if curNum+addNum > armLimit {
  134. addNum = armLimit - curNum
  135. }
  136. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  137. conscript := mapPlayerStorageTable.Storage.CurrencyMap.GetEntity(armID)
  138. conscript.Num += addNum
  139. mapPlayerStorageTable.Save2Queue()
  140. clog.Debugf("[doConscriptSettle] playerID = %d, armID = %d, addNum = %d", playerID, armID, addNum)
  141. // 推送兵力变更
  142. storage.Service().ChangePush(playerID, armID)
  143. progress := int32(addNum)
  144. // 增加征兵进度
  145. mapPlayerTable.Conscripts.AddConscriptProgress(progress)
  146. // 当前征兵/升级完成
  147. if mapPlayerTable.Conscripts.Conscript.IsConscriptFinish() {
  148. // 提交事件
  149. capp.PostEvent(event.NewConscriptTroopSettle(playerID, armID, mapPlayerTable.Conscripts.Conscript.Total))
  150. // 系统消息
  151. actorRemote.GamePlayer.GamePlayerCallSystemMsg(mapPlayerTable.GameNodeID, playerID, enum.ChatMsgType_conscript, nil, nil, armID, mapPlayerTable.Conscripts.Conscript.Total)
  152. // 如果没有设置自动补兵 则重置
  153. if !mapPlayerTable.Conscripts.Conscript.AutoConscript {
  154. mapPlayerTable.Conscripts.ResetConscript()
  155. } else {
  156. mapPlayerTable.Conscripts.Conscript.Total = 0
  157. mapPlayerTable.Conscripts.Conscript.Progress = 0
  158. }
  159. }
  160. return true
  161. }
  162. // 执行士兵升级结算
  163. func (p *service) doConscriptUpSettle(mapPlayerTable *db.MapPlayerTable, second int32) bool {
  164. var (
  165. playerID = mapPlayerTable.PlayerID
  166. upArmID = mapPlayerTable.Conscripts.ConscriptUp.UpArmID
  167. remain = int64(mapPlayerTable.Conscripts.ConscriptUp.ConscriptUpRemain())
  168. )
  169. if upArmID <= 0 || remain <= 0 {
  170. return false
  171. }
  172. upArmLevelRow, found := data.ArmLevel.GetByID(upArmID)
  173. if !found {
  174. clog.Warnf("[doConscriptUpSettle] up arm level config not found. playerID:%d,upArmID:%d", playerID, upArmID)
  175. return false
  176. }
  177. var (
  178. // 预备兵上限
  179. armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit)
  180. // 获取征兵/升级的士兵当前数量
  181. curNum = p.GetCurTroopNum(playerID)
  182. )
  183. // 判断如果数量已达上限 则更新时间 不结算
  184. if curNum >= armLimit {
  185. return false
  186. }
  187. // 获得兵力= 结算次数 * 结算时间 * 单次兵力
  188. addNum := p.calConscriptNumSecond(mapPlayerTable, second*upArmLevelRow.ConscriptNumSecond)
  189. if addNum <= 0 {
  190. clog.Warnf("[doConscriptUpSettle] calConscriptNumSecond num <=0. playerID:%d", mapPlayerTable.PlayerID)
  191. return false
  192. }
  193. if addNum >= remain {
  194. addNum = remain
  195. }
  196. // 修正添加数量
  197. addNum = math.Min(addNum, armLimit-curNum)
  198. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  199. conscript := mapPlayerStorageTable.Storage.CurrencyMap.GetEntity(upArmID)
  200. conscript.Num += addNum
  201. mapPlayerStorageTable.Save2Queue()
  202. clog.Debugf("[doConscriptUpSettle] playerID = %d, upArmID = %d, addNum = %d", playerID, upArmID, addNum)
  203. // 推送兵力变更
  204. storage.Service().ChangePush(playerID, upArmID)
  205. progress := int32(addNum)
  206. // 增加征兵进度
  207. mapPlayerTable.Conscripts.AddConscriptUpProgress(progress)
  208. // 当前征兵/升级完成
  209. if mapPlayerTable.Conscripts.ConscriptUp.IsConscriptUpFinish() {
  210. // 提交事件
  211. capp.PostEvent(event.NewConscriptTroopSettle(playerID, upArmID, mapPlayerTable.Conscripts.ConscriptUp.Total))
  212. actorRemote.GamePlayer.GamePlayerCallSystemMsg(mapPlayerTable.GameNodeID, playerID, enum.ChatMsgType_conscriptUp, nil, nil, upArmID, mapPlayerTable.Conscripts.ConscriptUp.Total)
  213. mapPlayerTable.Conscripts.ResetConscriptUp()
  214. }
  215. return true
  216. }
  217. // 计算征兵的数量
  218. func (p *service) calConscriptNumSecond(mapPlayerTable *db.MapPlayerTable, oneSecondNum int32) int64 {
  219. addRatio := float64(mapPlayerTable.Facilities.Attrs.Get(enum.AttrConscriptSpeed)) / constant.RatioBase
  220. singleAdd := math.Round[float64, int64]((1 + addRatio) * float64(oneSecondNum))
  221. return singleAdd
  222. }
  223. // 执行自动征兵 默认都是征兵 没有升级
  224. func (p *service) AutoConscript(mapPlayerTable *db.MapPlayerTable, armID int32) bool {
  225. playerID := mapPlayerTable.PlayerID
  226. armLevelRow, found := data.ArmLevel.GetByID(armID)
  227. if !found {
  228. clog.Warnf("auto conscript arm level config not found. armID:%d", armID)
  229. return false
  230. }
  231. var (
  232. // 预备兵上限
  233. armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit)
  234. // 获取征兵/升级的士兵当前数量
  235. curNum = p.GetCurTroopNum(playerID) + int64(mapPlayerTable.Conscripts.Conscript.ConscriptRemain())
  236. // 征兵数量
  237. conscriptNum = armLimit - curNum
  238. )
  239. // 当前数量已达上限 跳过
  240. if conscriptNum <= 0 {
  241. return false
  242. }
  243. // 获取当前征兵消耗
  244. for _, item := range armLevelRow.ConscriptCostItems {
  245. // 获取当前资源数量
  246. curNum := mapFacade.Storage.Get(playerID, item.ID)
  247. if curNum <= 0 {
  248. return false
  249. }
  250. // 当前道具可征兵数量
  251. diffNum := curNum / item.Num
  252. if diffNum <= 0 {
  253. return false
  254. }
  255. conscriptNum = math.Min(conscriptNum, diffNum)
  256. }
  257. if conscriptNum <= 0 {
  258. return false
  259. }
  260. // 计算征兵消耗
  261. costs := armLevelRow.CalConscriptAssets(conscriptNum)
  262. // 扣除资源
  263. _, errCode := mapFacade.Storage.AssetSubs(playerID, costs, ao.ConscriptCost)
  264. if code.IsFail(errCode) {
  265. return false
  266. }
  267. // 开始征兵
  268. mapPlayerTable.Conscripts.StartConscript(armID, int32(conscriptNum))
  269. return true
  270. }
  271. // 获取当前预备兵数量
  272. func (p *service) GetCurTroopNum(playerID int64) int64 {
  273. total := int64(0)
  274. for _, armLevelRow := range data.ArmLevel.List() {
  275. // TODO 暂时调用game player的service等背包迁移到地图 获取当前资源数量
  276. total += mapFacade.Storage.Get(playerID, armLevelRow.ID)
  277. }
  278. return total
  279. }