player_map.go 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465
  1. package mapPlayer
  2. import (
  3. capp "f1-game/internal/cherry_app"
  4. "f1-game/internal/code"
  5. "f1-game/internal/component/redis"
  6. "f1-game/internal/constant"
  7. "f1-game/internal/data"
  8. "f1-game/internal/enum"
  9. "f1-game/internal/event"
  10. nameActor "f1-game/internal/name/actor"
  11. nameLocal "f1-game/internal/name/local"
  12. nameRedis "f1-game/internal/name/redis"
  13. nameRemote "f1-game/internal/name/remote"
  14. nameRoute "f1-game/internal/name/route"
  15. "f1-game/internal/pb"
  16. "f1-game/internal/sessions"
  17. "f1-game/internal/types"
  18. ao "f1-game/nodes/game/player/asset/origin"
  19. mapCall "f1-game/nodes/map/internal/call"
  20. "f1-game/nodes/map/internal/db"
  21. dbMapPlayer "f1-game/nodes/map/internal/db/data/player"
  22. mapFacade "f1-game/nodes/map/internal/facade"
  23. mapTypes "f1-game/nodes/map/internal/types"
  24. "f1-game/nodes/map/player/battle"
  25. "f1-game/nodes/map/player/facility"
  26. "f1-game/nodes/map/player/player"
  27. "f1-game/nodes/map/player/scout"
  28. "f1-game/nodes/map/player/storage"
  29. "f1-game/nodes/map/player/team"
  30. ctime "github.com/cherry-game/cherry/extend/time"
  31. cfacade "github.com/cherry-game/cherry/facade"
  32. clog "github.com/cherry-game/cherry/logger"
  33. cproto "github.com/cherry-game/cherry/net/proto"
  34. )
  35. func (p *actorPlayer) initMap() {
  36. p.Local().Register(nameLocal.MapPlayer_Login, p.login)
  37. p.Local().Register(nameLocal.MapPlayer_Enter, p.enter)
  38. p.Local().Register(nameLocal.MapPlayer_SelectState, p.selectState)
  39. p.Local().Register(nameLocal.MapPlayer_BornStateInfo, p.bornStateInfo)
  40. p.Local().Register(nameLocal.MapPlayer_Join, p.join)
  41. p.Local().Register(nameLocal.MapPlayer_Quit, p.quit)
  42. p.Local().Register(nameLocal.MapPlayer_Slide, p.slide)
  43. p.Local().Register(nameLocal.MapPlayer_March, p.march)
  44. p.Local().Register(nameLocal.MapPlayer_Retreat, p.retreat)
  45. p.Local().Register(nameLocal.MapPlayer_MarchStop, p.marchStop)
  46. p.Local().Register(nameLocal.MapPlayer_Discard, p.discard)
  47. p.Local().Register(nameLocal.MapPlayer_DiscardCancel, p.discardCancel)
  48. p.Local().Register(nameLocal.MapPlayer_Build, p.build)
  49. p.Local().Register(nameLocal.MapPlayer_BuildUpgrade, p.buildUpgrade)
  50. p.Local().Register(nameLocal.MapPlayer_Relocate, p.relocate)
  51. p.Local().Register(nameLocal.MapPlayer_Comeback, p.comeback)
  52. p.Local().Register(nameLocal.MapPlayer_Reborn, p.reborn)
  53. p.Local().Register(nameLocal.MapPlayer_MapMark, p.mapMark)
  54. p.Local().Register(nameLocal.MapPlayer_MapMarkDelete, p.mapMarkDelete)
  55. p.Local().Register(nameLocal.MapPlayer_SiegeAssemble, p.siegeAssemble)
  56. p.Local().Register(nameLocal.MapPlayer_SiegeRank, p.siegeRank)
  57. p.Local().Register(nameLocal.MapPlayer_FindPath, p.findPath)
  58. p.Local().Register(nameLocal.MapPlayer_OccupyCastleList, p.occupyCastleList)
  59. p.Local().Register(nameLocal.MapPlayer_ScoutRequest, p.scoutRequest)
  60. p.Local().Register(nameLocal.MapPlayer_Reinforce, p.reinforce)
  61. p.Local().Register(nameLocal.MapPlayer_ReinforceCancel, p.reinforceCancel)
  62. p.Local().Register(nameLocal.MapPlayer_ResArmies, p.resArmies)
  63. p.Remote().Register(nameRemote.MapPlayer_AutoRetreat, p.autoRetreat)
  64. p.Remote().Register(nameRemote.MapPlayer_AutoReborn, p.autoReborn)
  65. p.Remote().Register(nameRemote.MapPlayer_UpdatePrestige, p.updatePrestige)
  66. p.Remote().Register(nameRemote.MapPlayer_MainCitySiege, p.mainCitySiege)
  67. p.Remote().Register(nameRemote.MapPlayer_UpdateWatcherPoint, p.updateWatcherPoint)
  68. p.Remote().Register(nameRemote.MapPlayer_AutoDefendQuit, p.autoDefendQuit)
  69. p.Remote().Register(nameRemote.MapPlayer_AutoDefendRequest, p.autoDefendRequest)
  70. p.Remote().Register(nameRemote.MapPlayer_ResOccupy, p.resOccupy)
  71. p.Remote().Register(nameRemote.MapPlayer_ResUpdate, p.resUpdate)
  72. p.Remote().Register(nameRemote.MapScout_UpdateNotice, p.scoutUpdateNotice)
  73. p.Remote().Register(nameRemote.MapScout_Seach, p.scoutSearch)
  74. p.Remote().Register(nameRemote.MapScout_SeachResult, p.scoutSearchResult)
  75. p.Remote().Register(nameRemote.MapPlayer_NotifyRebornPush, p.notifyRebornPush)
  76. }
  77. // login 玩家登录地图
  78. func (p *actorPlayer) login(session *cproto.Session, _ *pb.None) {
  79. clog.Debugf("player login map: %d", p.playerID)
  80. if p.isOnline {
  81. p.ResponseCode(session, code.OK)
  82. return
  83. }
  84. p.updateNowTime()
  85. // 检查玩家表是否存在,没有则创建
  86. playerTable, isNewPlayer := db.CheckMapPlayerTable(p.playerID)
  87. if isNewPlayer {
  88. session.Add(sessions.IsNewPlayer, isNewPlayer)
  89. }
  90. clog.Debugf("[login] Player enter map success: playerID = %d, objectID = %d", p.playerID)
  91. p.onReset(playerTable, true)
  92. // 登录前事件处理
  93. mapFacade.ServiceOnLogin(playerTable, session)
  94. // 推送各个模块数据
  95. mapFacade.ServicePush(playerTable, session)
  96. // 设置actor为登录状态
  97. p.isOnline = true
  98. // 返回玩家地图的信息
  99. p.Response(session, playerTable.ToMapLoginResponse())
  100. // 在线状态设置后,再启动定时器
  101. p.startTimer()
  102. // 登录后事件处理
  103. mapFacade.ServiceOnLogined(playerTable, session)
  104. }
  105. // enter 玩家进入地图
  106. func (p *actorPlayer) enter(session *cproto.Session, _ *pb.None) {
  107. clog.Debugf("player enter map: %d", p.playerID)
  108. if !p.isOnline {
  109. p.ResponseCode(session, code.PlayerNotLogin)
  110. return
  111. }
  112. playerTable := db.GetMapPlayerTable(p.playerID)
  113. // 未选择出生州
  114. if playerTable.BornStateID == 0 {
  115. p.ResponseCode(session, code.Map_NotSelectState)
  116. return
  117. }
  118. errCode := mapCall.Logic.Enter(p.playerID)
  119. p.ResponseCode(session, errCode)
  120. }
  121. // selectState 选择出生州,只在玩家首次进入地图时调用
  122. // 后序跨逻辑调选州再起
  123. func (p *actorPlayer) selectState(session *cproto.Session, req *pb.I32) {
  124. playerTable := db.GetMapPlayerTable(p.playerID)
  125. if playerTable.BornStateID != 0 {
  126. p.ResponseCode(session, code.Map_AlreadySelectState)
  127. return
  128. }
  129. arg := &pb.SelectStateRequest{
  130. StateID: req.Value,
  131. PlayerID: p.playerID,
  132. LeagueID: playerTable.LeagueID,
  133. }
  134. // 新玩家从 redis 获取一次数据
  135. playerData := redis.Game.GetPlayerData(p.playerID, nameRedis.PlayerInfoFields...)
  136. if playerData != nil {
  137. arg.PlayerName = playerData.PlayerName
  138. arg.IconID = playerData.IconID
  139. arg.FrameID = playerData.FrameID
  140. }
  141. // 调用 logic 选择出生州
  142. rsp, errCode := mapCall.Logic.SelectState(arg)
  143. if code.IsFail(errCode) {
  144. p.ResponseCode(session, errCode)
  145. return
  146. }
  147. // 更新出生州ID
  148. playerTable.ObjectID = rsp.ObjectID
  149. playerTable.SetPoint(rsp.Point.X, rsp.Point.Y)
  150. playerTable.BornStateID = req.Value
  151. playerTable.Save2Queue()
  152. p.ResponseCode(session, code.OK)
  153. }
  154. // bornStateInfo 获取出生州信息
  155. func (p *actorPlayer) bornStateInfo(session *cproto.Session, _ *pb.None) {
  156. rsp, errCode := mapCall.Logic.BornStateInfo()
  157. if code.IsFail(errCode) {
  158. p.ResponseCode(session, errCode)
  159. return
  160. }
  161. p.Response(session, rsp)
  162. }
  163. // join 以观察者进入地图
  164. func (p *actorPlayer) join(session *cproto.Session, _ *pb.None) {
  165. clog.Debugf("player join map: %d", p.playerID)
  166. playerTable := db.GetMapPlayerTable(p.playerID)
  167. mapCall.AOI.Enter(playerTable.ToAOIWatcher())
  168. }
  169. // quit 以观察者退出地图
  170. func (p *actorPlayer) quit(session *cproto.Session, _ *pb.None) {
  171. clog.Debugf("player quit map: %d", p.playerID)
  172. playerTable := db.GetMapPlayerTable(p.playerID)
  173. mapCall.AOI.Leave(playerTable.ObjectID, enum.ObjectType_Player)
  174. }
  175. // slide 滑动屏幕
  176. func (p *actorPlayer) slide(session *cproto.Session, req *pb.Point) {
  177. clog.Debugf("player slide: %d %v", p.playerID, req)
  178. playerTable := db.GetMapPlayerTable(p.playerID)
  179. aoiRequest := mapTypes.NewAOIRequest(p.playerID, playerTable.ObjectID, enum.ObjectType_Player, req.X, req.Y, true)
  180. mapCall.AOI.Move(aoiRequest)
  181. }
  182. // march 行军
  183. func (p *actorPlayer) march(session *cproto.Session, req *pb.MapMarchRequest) {
  184. marchType := enum.MarchType(req.MarchType)
  185. // 检查是否为不支持的行军类型
  186. if enum.IsNotAllowMarchType(marchType) {
  187. p.ResponseCode(session, code.MapUnsupportMarchType)
  188. return
  189. }
  190. playerTable := db.GetMapPlayerTable(p.playerID)
  191. dbTeam, ok := playerTable.Teams.GetTeam(req.TeamID)
  192. if !ok {
  193. p.ResponseCode(session, code.MapTeamNotFound)
  194. return
  195. }
  196. if errCode := dbTeam.IsBusy(); code.IsFail(errCode) {
  197. p.ResponseCode(session, errCode)
  198. return
  199. }
  200. var startPoint types.Point
  201. if dbTeam.IsNeedSync() {
  202. startPoint.Set(&playerTable.Point)
  203. } else {
  204. // 获取行军对象坐标
  205. errCode := mapCall.Logic.GetObject1Point(dbTeam.MarchObjectID, enum.ObjectType_March, &startPoint)
  206. if code.IsFail(errCode) {
  207. p.ResponseCode(session, errCode)
  208. return
  209. }
  210. }
  211. // 寻路
  212. path, errCode := mapCall.PathFind.Find(startPoint.X, startPoint.Y, req.Point.X, req.Point.Y, p.playerID, playerTable.LeagueID, marchType)
  213. if code.IsFail(errCode) {
  214. p.ResponseCode(session, errCode)
  215. return
  216. }
  217. // 检查消耗
  218. errCode = team.Service().CheckMarchCost(p.playerID, req.TeamID, marchType, len(path))
  219. if code.IsFail(errCode) {
  220. p.ResponseCode(session, errCode)
  221. return
  222. }
  223. // 调用地图行军
  224. arg := &pb.MarchRequest{
  225. TeamID: dbTeam.TeamID,
  226. ObjectID: dbTeam.MarchObjectID,
  227. MarchType: req.MarchType,
  228. Point: req.Point,
  229. Path: path,
  230. IsAutoRetreat: req.IsAutoRetreat,
  231. TargetObjectID: req.TargetObjectID,
  232. }
  233. if dbTeam.IsNeedSync() {
  234. arg.MarchSync = team.Service().GetTeamMarchSyncProto(playerTable, dbTeam)
  235. }
  236. // 取消城外自动征兵
  237. p.marchOutsideTroopsCancel(playerTable, dbTeam)
  238. rsp, errCode := mapCall.Logic.March(arg)
  239. if code.IsFail(errCode) {
  240. p.ResponseCode(session, errCode)
  241. return
  242. }
  243. // 保存行军对象ID
  244. if dbTeam.MarchObjectID == 0 {
  245. dbTeam.MarchObjectID = rsp.Key
  246. }
  247. // 设置自动征兵
  248. dbTeam.IsAutoTroops = req.IsAutoConscript
  249. playerTable.Save2Queue()
  250. // 扣除资源
  251. team.Service().MarchCost(p.playerID, req.TeamID, marchType, len(path))
  252. // 更新队伍状态
  253. team.Service().UpdateTeamStateByMarchState(playerTable, dbTeam, enum.MarchState(rsp.Value))
  254. p.ResponseCode(session, code.OK)
  255. }
  256. // retreat 主动回城
  257. func (p *actorPlayer) retreat(session *cproto.Session, req *pb.I32I64) {
  258. var (
  259. teamID = req.Key
  260. redeployObjectID = req.Value
  261. )
  262. playerTable := db.GetMapPlayerTable(p.playerID)
  263. dbTeam, ok := playerTable.Teams.GetTeam(teamID)
  264. if !ok {
  265. p.ResponseCode(session, code.MapTeamNotFound)
  266. return
  267. }
  268. if dbTeam.IsStandby() {
  269. p.ResponseCode(session, code.OK)
  270. return
  271. }
  272. var (
  273. startPoint types.Point
  274. endPoint types.Point
  275. )
  276. // 没有传入调动对象ID,就回主城
  277. // 撤退回主城是不是就要把调动值清除了?
  278. if redeployObjectID == 0 {
  279. // 默认回主城,只拿部队的坐标
  280. endPoint.Set(&playerTable.Point)
  281. errCode := mapCall.Logic.GetObject1Point(dbTeam.MarchObjectID, enum.ObjectType_March, &startPoint)
  282. if code.IsFail(errCode) {
  283. p.ResponseCode(session, errCode)
  284. return
  285. }
  286. // 把部队的调动信息删除
  287. dbTeam.RedeployObject.Set(0, 0)
  288. playerTable.Save2Queue()
  289. } else {
  290. // 回调动点
  291. if redeployObjectID != dbTeam.RedeployObject.Key {
  292. p.ResponseCode(session, code.MapRetreat_NotRedeploy)
  293. return
  294. }
  295. // 获取行军对象和调动点的坐标
  296. var (
  297. marchObject = enum.NewObject(dbTeam.MarchObjectID, enum.ObjectType_March)
  298. redeployObject = enum.NewObject(redeployObjectID, dbTeam.RedeployObject.Value)
  299. errCode = mapCall.Logic.GetObject2Point(marchObject, redeployObject, &startPoint, &endPoint)
  300. )
  301. if code.IsFail(errCode) {
  302. p.ResponseCode(session, errCode)
  303. return
  304. }
  305. }
  306. // 取消城外自动征兵
  307. p.marchOutsideTroopsCancel(playerTable, dbTeam)
  308. // 寻路
  309. path, errCode := mapCall.PathFind.Find(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y, p.playerID, playerTable.LeagueID, enum.MarchType_Retreat)
  310. if code.IsFail(errCode) {
  311. p.ResponseCode(session, errCode)
  312. return
  313. }
  314. // 调用地图行军
  315. arg := &pb.MarchRequest{
  316. TeamID: dbTeam.TeamID,
  317. ObjectID: dbTeam.MarchObjectID,
  318. MarchType: int32(enum.MarchType_Retreat),
  319. Point: endPoint.ToProto(),
  320. Path: path,
  321. RetreatState: int32(enum.MarchState_Retreat),
  322. TargetObjectID: redeployObjectID, // 如果是0,要在 logic 判断撤退的目标
  323. }
  324. rsp, errCode := mapCall.Logic.Retreat(arg)
  325. if code.IsFail(errCode) {
  326. p.ResponseCode(session, errCode)
  327. return
  328. }
  329. // 更新队伍状态
  330. team.Service().UpdateTeamStateByMarchState(playerTable, dbTeam, enum.MarchState(rsp.Value))
  331. p.ResponseCode(session, code.OK)
  332. }
  333. // 行军中止
  334. func (p *actorPlayer) marchStop(session *cproto.Session, req *pb.I32) {
  335. playerTable := db.GetMapPlayerTable(p.playerID)
  336. march, ok := playerTable.Teams.GetTeam(req.Value)
  337. if !ok {
  338. p.ResponseCode(session, code.MapTeamNotFound)
  339. return
  340. }
  341. errCode := mapCall.Logic.MarchStop(march.MarchObjectID)
  342. if code.IsFail(errCode) {
  343. p.ResponseCode(session, errCode)
  344. return
  345. }
  346. p.ResponseCode(session, code.OK)
  347. }
  348. // discard 放弃地图上的对象
  349. func (p *actorPlayer) discard(session *cproto.Session, req *pb.I64I32) {
  350. var (
  351. objectID = req.Key
  352. objectType = enum.ObjectType(req.Value)
  353. )
  354. // 放弃资源
  355. if objectType == enum.ObjectType_Res {
  356. errCode := mapCall.Logic.ResDiscard(p.playerID, objectID)
  357. p.ResponseCode(session, errCode)
  358. return
  359. }
  360. // 放弃建筑
  361. if objectType == enum.ObjectType_Build {
  362. _, errCode := mapCall.Logic.BuildDiscard(p.playerID, objectID)
  363. p.ResponseCode(session, errCode)
  364. return
  365. }
  366. p.ResponseCode(session, code.MapObjectTypeUnkown)
  367. }
  368. // discardCancel 取消放弃对象
  369. func (p *actorPlayer) discardCancel(session *cproto.Session, req *pb.I64I32) {
  370. var (
  371. objectID = req.Key
  372. objectType = req.Value
  373. )
  374. p.Debug("discardCancel playerID: %d, objectID: %d, objectType: %s", p.playerID, objectID, enum.GetObjectTypeName(enum.ObjectType(objectType)))
  375. errCode := mapCall.Logic.DiscardCancelPlayer(p.playerID, objectID, objectType)
  376. p.ResponseCode(session, errCode)
  377. }
  378. func (p *actorPlayer) build(session *cproto.Session, req *pb.MapBuildRequest) {
  379. row, ok := data.MapBuild.GetByConfigID(req.ConfigID)
  380. if !ok {
  381. p.ResponseCode(session, code.ConfigNotFound_MapBuild)
  382. return
  383. }
  384. if row.BuildType != enum.BuildType_Player {
  385. p.ResponseCode(session, code.MapBuild_NotPlayerBuild)
  386. return
  387. }
  388. playerTable := db.GetMapPlayerTable(p.playerID)
  389. // 如果当前建造的是玩家地基 需要判断是否在冷却时间内
  390. if req.ConfigID == constant.MapBuild_CityBase && playerTable.Builds.IsCityBaseCooldowning() {
  391. p.ResponseCode(session, code.MapBuild_FoundateCooldown)
  392. return
  393. }
  394. if ok := mapFacade.Storage.IsAllEnough(p.playerID, row.BuildCost); !ok {
  395. p.ResponseCode(session, code.ItemNotEnough)
  396. return
  397. }
  398. var (
  399. buildCount = playerTable.Builds.GetBuildCount(req.ConfigID)
  400. buildCountLimit = facility.Service().GetBuildCountLimit(playerTable, row)
  401. )
  402. // 计算建造时间
  403. buildTime := row.BuildTime
  404. // 首次建造
  405. if buildCount == 0 {
  406. if time, ok := data.Const.MapBuildFirstTimeElapsed[req.ConfigID]; ok {
  407. buildTime = time
  408. }
  409. }
  410. arg := pb.BuildRequest{
  411. ConfigID: req.ConfigID,
  412. PlayerID: p.playerID,
  413. LeagueID: playerTable.LeagueID,
  414. X: req.Point.X,
  415. Y: req.Point.Y,
  416. BuildEndTime: ctime.Now().ToMillisecond() + buildTime*ctime.MillisecondsPerSecond,
  417. BuildLimit: buildCountLimit,
  418. }
  419. _, errCode := mapCall.Logic.Build(&arg)
  420. if code.IsFail(errCode) {
  421. p.ResponseCode(session, errCode)
  422. return
  423. }
  424. // 扣除道具
  425. mapFacade.Storage.AssetSubs(p.playerID, row.BuildCost, ao.None, true)
  426. // 增加建筑数量
  427. playerTable.Builds.AddBuildCount(req.ConfigID)
  428. resp := &pb.I64{}
  429. // 记录地基建造冷却时间戳
  430. if req.ConfigID == constant.MapBuild_CityBase {
  431. playerTable.Builds.CityBaseEndTime = ctime.Now().ToMillisecond() + data.Const.GetMapCityBaseCooldown()
  432. resp.Value = playerTable.Builds.CityBaseEndTime
  433. }
  434. playerTable.Save2Queue()
  435. p.Response(session, resp)
  436. }
  437. // 玩家建筑升级
  438. func (p *actorPlayer) buildUpgrade(session *cproto.Session, req *pb.MapBuildUpgradeRequest) {
  439. var (
  440. objectID = req.ObjectID
  441. configID = req.ConfigID
  442. level = req.Level
  443. )
  444. mapBuildRow, found := data.MapBuild.GetByConfigID(configID)
  445. if !found {
  446. p.ResponseCode(session, code.ConfigNotFound_MapBuild)
  447. return
  448. }
  449. // 不是玩家建筑
  450. if mapBuildRow.BuildType != enum.BuildType_Player {
  451. p.ResponseCode(session, code.MapBuild_NotPlayerBuild)
  452. return
  453. }
  454. mapBuildUpgradeRow, found := data.MapBuildUpgrade.GetByConfigIDLevel(configID, level)
  455. if !found {
  456. p.ResponseCode(session, code.ConfigNotFound_MapBuildUpgrade)
  457. return
  458. }
  459. if ok := mapFacade.Storage.IsAllEnough(p.playerID, mapBuildUpgradeRow.UpgradeCost); !ok {
  460. p.ResponseCode(session, code.ItemNotEnough)
  461. return
  462. }
  463. arg := &pb.BuildUpgradeRequest{
  464. ObjectID: objectID,
  465. ConfigID: configID,
  466. PlayerID: p.playerID,
  467. Level: level,
  468. UpgradeEndTime: ctime.Now().ToMillisecond() + mapBuildUpgradeRow.UpgradeTime*ctime.MillisecondsPerSecond,
  469. }
  470. errCode := mapCall.Logic.BuildUpgrade(arg)
  471. if code.IsFail(errCode) {
  472. p.ResponseCode(session, errCode)
  473. return
  474. }
  475. mapFacade.Storage.AssetSubs(p.playerID, mapBuildUpgradeRow.UpgradeCost, ao.None, true)
  476. p.ResponseCode(session, code.OK)
  477. }
  478. // relocate 玩家迁城
  479. func (p *actorPlayer) relocate(session *cproto.Session, req *pb.I64) {
  480. // 判断是否可以迁城
  481. if errCode := p.relocatable(); code.IsFail(errCode) {
  482. p.ResponseCode(session, errCode)
  483. return
  484. }
  485. cityBaseObjectID := req.Value
  486. point, errCode := mapCall.Logic.Relocate(p.playerID, cityBaseObjectID)
  487. if code.IsFail(errCode) {
  488. p.ResponseCode(session, errCode)
  489. return
  490. }
  491. playerTable := db.GetMapPlayerTable(p.playerID)
  492. // 如果玩家存在联盟 删除驻地信息
  493. if playerTable.LeagueID > 0 {
  494. removeReq := &pb.I64{Value: p.playerID}
  495. target := cfacade.NewChildPath("", nameActor.Map_League, playerTable.LeagueID)
  496. capp.Call(target, nameRemote.MapLeague_ResidenceRemove, removeReq)
  497. }
  498. // 更新迁城冷却时间
  499. playerTable.Builds.RelocateEndTime = p.now.ToMillisecond() + data.Const.GetMapRelocateCooldown()
  500. playerTable.SetPoint(point.X, point.Y)
  501. playerTable.Save2Queue()
  502. resp := &pb.I64{
  503. Value: playerTable.Builds.RelocateEndTime,
  504. }
  505. p.Response(session, resp)
  506. }
  507. func (p *actorPlayer) relocatable() int32 {
  508. p.updateNowTime()
  509. playerTable := db.GetMapPlayerTable(p.playerID)
  510. // 迁城冷却中
  511. if playerTable.Builds.RelocateEndTime > p.now.ToMillisecond() {
  512. return code.MapRelocate_Cooldown
  513. }
  514. // 没有加入联盟,不能迁城
  515. if playerTable.LeagueID == 0 {
  516. return code.MapRelocate_NoLeague
  517. }
  518. // TODO 其它限制,比如:主城被攻击,攻城时间
  519. return code.OK
  520. }
  521. // comeback 玩家再起
  522. func (p *actorPlayer) comeback(session *cproto.Session, req *pb.I32Bool) {
  523. var (
  524. stateID = req.Key // 州ID
  525. rechoose = req.Value // 是否重新选州
  526. )
  527. p.Debug("[comeback] stateID = %d, rechoose = %v", stateID, rechoose)
  528. // 再起冷却中
  529. playerTable := db.GetMapPlayerTable(p.playerID)
  530. p.updateNowTime()
  531. if playerTable.Builds.ComebackEndTime > p.now.ToMillisecond() {
  532. p.ResponseCode(session, code.MapComeback_Cooldown)
  533. return
  534. }
  535. if rechoose {
  536. // 不能重选当前州
  537. if stateID == playerTable.BornStateID {
  538. p.ResponseCode(session, code.MapComeback_SameState)
  539. return
  540. }
  541. // 需要退联盟
  542. if playerTable.LeagueID != 0 {
  543. p.ResponseCode(session, code.MapComeback_NeedLeagueQuit)
  544. return
  545. }
  546. } else {
  547. // 非重新选州,使用当前出生州
  548. stateID = playerTable.BornStateID
  549. }
  550. point, errCode := mapCall.Logic.Comeback(p.playerID, rechoose, stateID)
  551. if code.IsFail(errCode) {
  552. p.ResponseCode(session, errCode)
  553. return
  554. }
  555. playerTable.Builds.ComebackEndTime = p.now.ToMillisecond() + data.Const.GetMapComebackCoolDown()
  556. player.Service().UpdateWatcherPoint(playerTable, point.X, point.Y)
  557. // 如果玩家存在联盟 删除驻地信息
  558. if playerTable.LeagueID > 0 {
  559. removeReq := &pb.I64{Value: p.playerID}
  560. target := cfacade.NewChildPath("", nameActor.Map_League, playerTable.LeagueID)
  561. capp.Call(target, nameRemote.MapLeague_ResidenceRemove, removeReq)
  562. }
  563. rsp := pb.ComebackResponse{
  564. Point: point,
  565. ComebackEndTime: playerTable.Builds.ComebackEndTime,
  566. }
  567. p.Response(session, &rsp)
  568. }
  569. // autoReborn 玩家自动重新出生
  570. func (p *actorPlayer) autoReborn() {
  571. p.Debug("[autoReborn]")
  572. playerTable := db.GetMapPlayerTable(p.playerID)
  573. if playerTable.BornStateID == 0 {
  574. p.Warn("[autoReborn] player not select state")
  575. return
  576. }
  577. point, errCode := mapCall.Logic.Reborn(p.playerID, playerTable.BornStateID)
  578. if code.IsFail(errCode) {
  579. p.Debug("[autoReborn] errCode = %d", errCode)
  580. // 重新出生失败,保存失败信息,以待重试
  581. playerTable.IsRebornFailed = true
  582. playerTable.Save2Queue()
  583. // 推送通知
  584. if p.isOnline {
  585. sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_Reborn, playerTable.ToRebornPush())
  586. }
  587. return
  588. }
  589. // 更新坐标
  590. player.Service().UpdateWatcherPoint(playerTable, point.X, point.Y)
  591. // 推送重生
  592. if p.isOnline {
  593. sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_Reborn, &pb.RebornPush{
  594. Point: point,
  595. })
  596. } else {
  597. // 保存以登录时推送
  598. playerTable.RebornInfo = dbMapPlayer.NewRebornInfo(point.X, point.Y)
  599. playerTable.Save2Queue()
  600. }
  601. }
  602. // reborn 重新随机出生点
  603. func (p *actorPlayer) reborn(session *cproto.Session, _ *pb.None) {
  604. playerTable := db.GetMapPlayerTable(p.playerID)
  605. if !playerTable.IsRebornFailed {
  606. p.ResponseCode(session, code.OperationNotSupportYet)
  607. return
  608. }
  609. // 还有选过州,不能重新随机出生点
  610. if playerTable.BornStateID == 0 {
  611. p.ResponseCode(session, code.Map_NotSelectState)
  612. return
  613. }
  614. // 重新随机出生点
  615. point, errCode := mapCall.Logic.Reborn(p.playerID, playerTable.BornStateID)
  616. if code.IsFail(errCode) {
  617. p.ResponseCode(session, errCode)
  618. return
  619. }
  620. playerTable.ClearRebornInfo()
  621. player.Service().UpdateWatcherPoint(playerTable, point.X, point.Y)
  622. p.Response(session, point)
  623. }
  624. // autoRetreat 自动撤退
  625. // TODO 自动撤退的流程可以改一下,因为是地图上发过来的消息,所以应该是有部队的坐标和调动点的坐标的,
  626. // 应该带过来,这里就只做寻路就OK了
  627. func (p *actorPlayer) autoRetreat(req *pb.AutoRetreat) {
  628. var (
  629. teamID = req.TeamID
  630. marchState = enum.MarchState(req.MarchState)
  631. isRemoveRedeploy = req.IsRemoveRedeploy
  632. )
  633. playerTable := db.GetMapPlayerTable(p.playerID)
  634. dbTeam, ok := playerTable.Teams.GetTeam(teamID)
  635. if !ok {
  636. clog.Warnf("auto retreat team not found, teamID = %d", teamID)
  637. return
  638. }
  639. // 移除调动点
  640. if isRemoveRedeploy {
  641. dbTeam.RedeployObject.Set(0, 0)
  642. playerTable.Save2Queue()
  643. }
  644. var (
  645. startPoint types.Point
  646. endPoint types.Point
  647. )
  648. // 如果有调动点,就撤退回调动点,否则就撤退回主城
  649. if dbTeam.RedeployObject.Key == 0 {
  650. // 默认回主城,只拿部队的坐标
  651. endPoint.Set(&playerTable.Point)
  652. errCode := mapCall.Logic.GetObject1Point(dbTeam.MarchObjectID, enum.ObjectType_March, &startPoint)
  653. if code.IsFail(errCode) {
  654. clog.Warnf("[autoRetreat] get march point failed. teamID = %d, errCode = %d", teamID, errCode)
  655. return
  656. }
  657. } else {
  658. // 回调动点
  659. // 获取行军对象和调动点的坐标
  660. var (
  661. marchObject = enum.NewObject(dbTeam.MarchObjectID, enum.ObjectType_March)
  662. deployObject = enum.NewObject(dbTeam.RedeployObject.Key, dbTeam.RedeployObject.Value)
  663. errCode = mapCall.Logic.GetObject2Point(marchObject, deployObject, &startPoint, &endPoint)
  664. )
  665. if code.IsFail(errCode) {
  666. clog.Warnf("[autoRetreat] get object points failed. teamID = %d, RedeployObject = (%d, %s), errCode = %d",
  667. teamID, dbTeam.RedeployObject.Key, enum.GetObjectTypeName(dbTeam.RedeployObject.Value), errCode)
  668. return
  669. }
  670. }
  671. path, errCode := mapCall.PathFind.Find(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y, p.playerID, playerTable.LeagueID, enum.MarchType_Retreat)
  672. if code.IsFail(errCode) {
  673. clog.Warnf("auto retreat find path failed. teamID = %d, errCode = %d", teamID, errCode)
  674. return
  675. }
  676. // 调用地图行军
  677. arg := &pb.MarchRequest{
  678. TeamID: dbTeam.TeamID,
  679. ObjectID: dbTeam.MarchObjectID,
  680. MarchType: int32(enum.MarchType_Retreat),
  681. Point: endPoint.ToProto(),
  682. Path: path,
  683. IsAutoRetreat: true, // 自动撤退
  684. RetreatState: int32(marchState),
  685. TargetObjectID: dbTeam.RedeployObject.Key, // 如果是0,要在 logic 判断撤退的目标
  686. }
  687. rsp, errCode := mapCall.Logic.Retreat(arg)
  688. if code.IsFail(errCode) {
  689. clog.Warnf("auto retreat failed. teamID = %d, errCode = %d", teamID, errCode)
  690. return
  691. }
  692. team.Service().UpdateTeamStateByMarchState(playerTable, dbTeam, enum.MarchState(rsp.Value))
  693. // 取消自动征兵 如果存在
  694. p.marchOutsideTroopsCancel(playerTable, dbTeam)
  695. }
  696. // 更新声望
  697. func (p *actorPlayer) updatePrestige(req *pb.I32Map) {
  698. prestigeMap := map[enum.PrestigeType]int32{}
  699. for k, v := range req.Value {
  700. prestigeMap[enum.PrestigeType(k)] = v
  701. }
  702. player.Service().UpdatePrestige(p.playerID, prestigeMap)
  703. }
  704. // 地图标记
  705. func (p *actorPlayer) mapMark(session *cproto.Session, req *pb.MapMarkRequest) {
  706. var (
  707. playerTable = db.GetMapPlayerTable(p.playerID)
  708. title = req.Title
  709. point = req.Point
  710. update = false
  711. markID, ok = data.PointToTileID(point.X, point.Y)
  712. )
  713. // TODO 判断坐标是否正确
  714. if !ok {
  715. p.ResponseCode(session, code.MapGetPointFail)
  716. return
  717. }
  718. // 判断地图标记上限
  719. if playerTable.MapMarks.Size() >= data.Const.MapMarkNumLimit {
  720. p.ResponseCode(session, code.MapMark_NumLimit)
  721. return
  722. }
  723. // 判断标题长度是否合法
  724. if ok := data.Const.CheckMapMarkTitle(title); !ok {
  725. p.ResponseCode(session, code.MapMark_TitleLenLimit)
  726. return
  727. }
  728. mapMark, found := playerTable.MapMarks[markID]
  729. if !found {
  730. mapMark = &dbMapPlayer.MapMark{
  731. Title: title,
  732. Point: types.NewPoint(point.X, point.Y),
  733. }
  734. playerTable.MapMarks.Put(markID, mapMark)
  735. update = true
  736. }
  737. if mapMark.Title != title {
  738. mapMark.Title = title
  739. update = true
  740. }
  741. if update {
  742. // 更新标记时间戳
  743. mapMark.MarkTime = ctime.Now().ToSecond()
  744. playerTable.Save2Queue()
  745. }
  746. resp := mapMark.ToProto(markID)
  747. p.Response(session, resp)
  748. }
  749. // 地图标记删除
  750. func (p *actorPlayer) mapMarkDelete(session *cproto.Session, req *pb.I32) {
  751. var (
  752. playerTable = db.GetMapPlayerTable(p.playerID)
  753. markID = req.Value
  754. )
  755. _, found := playerTable.MapMarks.Get(markID)
  756. if !found {
  757. p.ResponseCode(session, code.MapMark_NotExist)
  758. return
  759. }
  760. playerTable.MapMarks.Remove(markID)
  761. playerTable.Save2Queue()
  762. p.ResponseCode(session, code.OK)
  763. }
  764. // 攻城集结
  765. func (p *actorPlayer) siegeAssemble(session *cproto.Session, req *pb.SiegeAssembleRequest) {
  766. p.updateNowTime()
  767. playerTable := db.GetMapPlayerTable(p.playerID)
  768. dbTeam, ok := playerTable.Teams.GetTeam(req.TeamID)
  769. if !ok {
  770. p.ResponseCode(session, code.MapTeamNotFound)
  771. return
  772. }
  773. if errCode := dbTeam.IsBusy(); code.IsFail(errCode) {
  774. p.ResponseCode(session, errCode)
  775. return
  776. }
  777. var (
  778. startPoint types.Point
  779. endPoint types.Point
  780. )
  781. // 如果是待命状态,行军点就是玩家当前位置
  782. if dbTeam.IsNeedSync() {
  783. startPoint = playerTable.Point
  784. // 只打目标集结点就够了
  785. errCode := mapCall.Logic.GetObject1Point(req.SiegeBaseObjectID, enum.ObjectType_Castle, &endPoint)
  786. if code.IsFail(errCode) {
  787. p.ResponseCode(session, errCode)
  788. return
  789. }
  790. } else {
  791. // 非待命状态,要找行军对象坐标和集结点坐标
  792. var (
  793. marchObject = enum.NewObject(dbTeam.MarchObjectID, enum.ObjectType_March)
  794. siegeObject = enum.NewObject(req.SiegeBaseObjectID, enum.ObjectType_Castle)
  795. errCode = mapCall.Logic.GetObject2Point(marchObject, siegeObject, &startPoint, &endPoint)
  796. )
  797. if code.IsFail(errCode) {
  798. p.ResponseCode(session, errCode)
  799. return
  800. }
  801. }
  802. path, errCode := mapCall.PathFind.Find(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y, p.playerID, playerTable.LeagueID, enum.MarchType_SiegeAssemble)
  803. if code.IsFail(errCode) {
  804. p.ResponseCode(session, errCode)
  805. return
  806. }
  807. // 检查资源是否足够
  808. errCode = team.Service().CheckMarchCost(p.playerID, req.TeamID, enum.MarchType_SiegeAssemble, len(path))
  809. if code.IsFail(errCode) {
  810. p.ResponseCode(session, errCode)
  811. return
  812. }
  813. // 调用地图行军
  814. arg := &pb.MarchRequest{
  815. TeamID: dbTeam.TeamID,
  816. ObjectID: dbTeam.MarchObjectID,
  817. MarchType: int32(enum.MarchType_SiegeAssemble),
  818. Point: endPoint.ToProto(),
  819. Path: path,
  820. IsMainForce: req.IsMainForce,
  821. TargetObjectID: req.SiegeBaseObjectID,
  822. }
  823. if dbTeam.IsNeedSync() {
  824. arg.MarchSync = team.Service().GetTeamMarchSyncProto(playerTable, dbTeam)
  825. }
  826. rsp, errCode := mapCall.Logic.SiegeAssemble(arg)
  827. if code.IsFail(errCode) {
  828. p.ResponseCode(session, errCode)
  829. return
  830. }
  831. if dbTeam.MarchObjectID == 0 {
  832. dbTeam.MarchObjectID = rsp.Key
  833. }
  834. // 更新部队调动对象
  835. dbTeam.RedeployObject.Set(req.SiegeBaseObjectID, enum.ObjectType_Castle)
  836. playerTable.Save2Queue()
  837. // 扣除资源
  838. team.Service().MarchCost(p.playerID, req.TeamID, enum.MarchType_SiegeAssemble, len(path))
  839. // 更新队伍状态
  840. team.Service().UpdateTeamStateByMarchState(playerTable, dbTeam, enum.MarchState(rsp.Value))
  841. p.ResponseCode(session, code.OK)
  842. }
  843. // 获取城池首占信息
  844. func (p *actorPlayer) siegeRank(session *cproto.Session, req *pb.I64) {
  845. rsp, errCode := mapCall.Logic.SiegeRank(req.Value)
  846. if code.IsFail(errCode) {
  847. p.ResponseCode(session, errCode)
  848. return
  849. }
  850. p.Response(session, rsp)
  851. }
  852. // 查询寻路信息
  853. func (p *actorPlayer) findPath(session *cproto.Session, req *pb.MapFindPathRequest) {
  854. playerTable := db.GetMapPlayerTable(p.playerID)
  855. dbTeam, ok := playerTable.Teams.GetTeam(req.TeamID)
  856. if !ok {
  857. p.ResponseCode(session, code.MapTeamNotFound)
  858. return
  859. }
  860. var startPoint types.Point
  861. if dbTeam.IsStandby() {
  862. startPoint.Set(&playerTable.Point)
  863. } else {
  864. // 获取行军对象坐标
  865. errCode := mapCall.Logic.GetObject1Point(dbTeam.MarchObjectID, enum.ObjectType_March, &startPoint)
  866. if code.IsFail(errCode) {
  867. p.ResponseCode(session, errCode)
  868. return
  869. }
  870. }
  871. paths, errCode := mapCall.PathFind.Find(startPoint.X, startPoint.Y, req.Point.X, req.Point.Y, p.playerID, playerTable.LeagueID, enum.MarchType_Retreat)
  872. if code.IsFail(errCode) {
  873. p.ResponseCode(session, errCode)
  874. return
  875. }
  876. rsp := &pb.Points{}
  877. for _, path := range paths {
  878. point := &pb.Point{
  879. X: path.X,
  880. Y: path.Y,
  881. }
  882. rsp.List = append(rsp.List, point)
  883. }
  884. p.Response(session, rsp)
  885. }
  886. func (p *actorPlayer) autoDefendQuit(req *pb.I32List) {
  887. clog.Debugf("[autoDefendQuit] req = %+v", req)
  888. playerTable := db.GetMapPlayerTable(p.playerID)
  889. // 自动防守退出
  890. for _, teamID := range req.List {
  891. dbTeam, ok := playerTable.Teams.GetTeam(teamID)
  892. if !ok {
  893. continue
  894. }
  895. dbTeam.IsAutoDefend = false
  896. }
  897. playerTable.Save2Queue()
  898. }
  899. // 玩家主城被攻打
  900. func (p *actorPlayer) mainCitySiege(req *pb.I64) {
  901. clog.Debugf("[mainCitySiege] ObjectID = %v", req.Value)
  902. playerTable := db.GetMapPlayerTable(p.playerID)
  903. // 获取所有在城内并且非重伤的部队去自动防守
  904. arg := &pb.AutoDefend{
  905. BuildObjectID: req.Value,
  906. }
  907. for _, dbTeam := range playerTable.Teams {
  908. if dbTeam.IsNotStandby() || code.IsFail(dbTeam.IsBusy()) || team.Service().IsTeamTroopsLack(playerTable, dbTeam) {
  909. continue
  910. }
  911. member := &pb.AutoDefendMember{
  912. MarchObjectID: dbTeam.MarchObjectID,
  913. }
  914. if dbTeam.IsNeedSync() {
  915. member.MarchSync = team.Service().GetTeamMarchSyncProto(playerTable, dbTeam)
  916. }
  917. arg.Members = append(arg.Members, member)
  918. }
  919. clog.Debugf("[mainCitySiege] ObjectID = %v, March size = %v", req.Value, len(arg.Members))
  920. // 通知加入自动防守
  921. if len(arg.Members) > 0 {
  922. rsp, errCode := mapCall.Logic.AutoDefend(arg)
  923. if code.IsFail(errCode) {
  924. clog.Warnf("[mainCitySiege] auto defend error: req = %+v, code = %v", arg, errCode)
  925. return
  926. }
  927. for _, pair := range rsp.List {
  928. if dbTeam, ok := playerTable.Teams.GetTeam(pair.Value); ok {
  929. if dbTeam.MarchObjectID == 0 {
  930. dbTeam.MarchObjectID = pair.Key
  931. }
  932. dbTeam.IsAutoDefend = true
  933. }
  934. }
  935. playerTable.Save2Queue()
  936. }
  937. }
  938. func (p *actorPlayer) updateWatcherPoint(req *pb.Point) {
  939. playerTable := db.GetMapPlayerTable(p.playerID)
  940. if playerTable == nil {
  941. return
  942. }
  943. p.Debug("update watcher point: %+v", req)
  944. player.Service().UpdateWatcherPoint(playerTable, req.X, req.Y)
  945. }
  946. // autoDefendNotice 自动防守通知
  947. func (p *actorPlayer) autoDefendRequest(req *pb.AutoDefendRequest) {
  948. clog.Debugf("[autoDefendRequest] req = %+v", req)
  949. playerTable := db.GetMapPlayerTable(p.playerID)
  950. // 获取所有在城内并且非重伤的部队去自动防守
  951. arg := &pb.AutoDefend{
  952. BuildObjectID: req.BuildObjectID,
  953. }
  954. for _, teamID := range req.TeamIDs {
  955. dbTeam, ok := playerTable.Teams.GetTeam(teamID)
  956. if !ok {
  957. continue
  958. }
  959. if dbTeam.IsAutoDefend || code.IsFail(dbTeam.IsBusy()) || team.Service().IsTeamTroopsLack(playerTable, dbTeam) {
  960. continue
  961. }
  962. member := &pb.AutoDefendMember{
  963. MarchObjectID: dbTeam.MarchObjectID,
  964. }
  965. arg.Members = append(arg.Members, member)
  966. }
  967. clog.Debugf("[autoDefendRequest] ObjectID = %v, Arg = %+v", req.BuildObjectID, arg)
  968. // 通知加入自动防守
  969. if len(arg.Members) > 0 {
  970. rsp, errCode := mapCall.Logic.AutoDefend(arg)
  971. if code.IsFail(errCode) {
  972. clog.Warnf("[autoDefendRequest] auto defend error: req = %+v, code = %v", arg, errCode)
  973. return
  974. }
  975. for _, pair := range rsp.List {
  976. if dbTeam, ok := playerTable.Teams.GetTeam(pair.Value); ok {
  977. dbTeam.IsAutoDefend = true
  978. }
  979. }
  980. playerTable.Save2Queue()
  981. }
  982. }
  983. func (p *actorPlayer) resOccupy(e cfacade.IEventData) {
  984. evt, ok := e.(*event.MapResOccupy)
  985. if !ok {
  986. p.Warn("[resOccupy] event type error. e = %+v", e)
  987. return
  988. }
  989. p.Debug("[resOccupy] %+v", evt)
  990. data := evt.Data()
  991. playerTable := db.GetMapPlayerTable(p.playerID)
  992. playerTable.ResMap.Put(data.ObjectID, &dbMapPlayer.Res{
  993. ObjectID: data.ObjectID,
  994. TileID: data.TileID,
  995. ConfigID: data.ConfigID,
  996. InLeagueArea: data.InLeagueArea,
  997. })
  998. // TODO 更新产量
  999. playerTable.Save2Queue()
  1000. }
  1001. func (p *actorPlayer) resUpdate(e cfacade.IEventData) {
  1002. evt, ok := e.(*event.MapResUpdate)
  1003. if !ok {
  1004. p.Warn("[resUpdate] event type error. e = %+v", e)
  1005. return
  1006. }
  1007. p.Debug("[resUpdate] %+v", evt)
  1008. data := evt.Data()
  1009. playerTable := db.GetMapPlayerTable(p.playerID)
  1010. res, ok := playerTable.ResMap.Get(data.ObjectID)
  1011. if !ok {
  1012. p.Warn("[resUpdate] res not found. e = %+v", e)
  1013. return
  1014. }
  1015. switch data.UpdateType {
  1016. case enum.ResUpdate_InLeagueArea:
  1017. res.InLeagueArea = data.InLeagueArea
  1018. case enum.ResUpdate_Delete:
  1019. playerTable.ResMap.Remove(data.ObjectID)
  1020. }
  1021. // TODO 更新产量
  1022. playerTable.Save2Queue()
  1023. }
  1024. // 获取攻占城池列表
  1025. func (p *actorPlayer) occupyCastleList(session *cproto.Session, _ *pb.None) {
  1026. // 请求logic 获取攻占城池列表
  1027. rsp, errCode := mapCall.Logic.OccupyCastleList()
  1028. if code.IsFail(errCode) {
  1029. p.ResponseCode(session, errCode)
  1030. return
  1031. }
  1032. p.Response(session, rsp)
  1033. }
  1034. // 主城加固
  1035. func (p *actorPlayer) reinforce(session *cproto.Session, _ *pb.None) {
  1036. errCode := mapCall.Logic.Reinforce(p.playerID)
  1037. p.ResponseCode(session, errCode)
  1038. }
  1039. // 主城加固取消
  1040. func (p *actorPlayer) reinforceCancel(session *cproto.Session, _ *pb.None) {
  1041. errCode := mapCall.Logic.ReinforceCancel(p.playerID)
  1042. p.ResponseCode(session, errCode)
  1043. }
  1044. // 获取资源守军
  1045. func (p *actorPlayer) resArmies(session *cproto.Session, req *pb.I64) {
  1046. rsp, errCode := mapCall.Logic.ResArmies(req)
  1047. if code.IsFail(errCode) {
  1048. p.ResponseCode(session, errCode)
  1049. return
  1050. }
  1051. p.Response(session, rsp)
  1052. }
  1053. // 发起侦察
  1054. func (p *actorPlayer) scoutRequest(session *cproto.Session, req *pb.I32I64) {
  1055. var (
  1056. playerTable = db.GetMapPlayerTable(p.playerID)
  1057. queueID = req.Key
  1058. objectID = req.Value
  1059. curTime = ctime.Now().ToMillisecond()
  1060. )
  1061. if objectID <= 0 {
  1062. p.ResponseCode(session, code.IllegalArgument)
  1063. return
  1064. }
  1065. // 侦察队列不存在
  1066. scout, found := playerTable.Scouts.GetScout(queueID)
  1067. if !found {
  1068. p.ResponseCode(session, code.ScoutQueueNotExist)
  1069. return
  1070. }
  1071. // 检测侦察队列是否正在使用
  1072. if scout.IsScouting(curTime) {
  1073. p.ResponseCode(session, code.ScoutQueueBusy)
  1074. return
  1075. }
  1076. // 去logic校验是否可侦察
  1077. resp, errCode := mapCall.Logic.ScoutCheck(p.playerID, objectID)
  1078. if code.IsFail(errCode) {
  1079. p.ResponseCode(session, errCode)
  1080. return
  1081. }
  1082. endTime := data.Const.GetMapScoutMarchTime()
  1083. // 更新当前为侦察-行军状态
  1084. errCode = mapCall.Scout.ScoutUpdateStatus(queueID, enum.ScoutType_March, p.playerID, endTime)
  1085. if code.IsFail(errCode) {
  1086. p.ResponseCode(session, errCode)
  1087. return
  1088. }
  1089. // 侦察消耗
  1090. _, errCode = storage.Service().AssetSubs(p.playerID, data.Const.MapScoutCosts, ao.MapScoutCost, true)
  1091. if code.IsFail(errCode) {
  1092. p.ResponseCode(session, errCode)
  1093. return
  1094. }
  1095. scout.TargetPlayerID = resp.TargetPlayerID
  1096. scout.Point = types.NewPoint(resp.Point.X, resp.Point.Y)
  1097. scout.EndTime = endTime
  1098. playerTable.Save2Queue()
  1099. proto := scout.ToScoutProto(queueID)
  1100. p.Response(session, proto)
  1101. }
  1102. // 开始侦察通知处理
  1103. func (p *actorPlayer) scoutUpdateNotice(req *pb.ScoutUpdateNotice) {
  1104. var (
  1105. starts = req.Starts
  1106. ends = req.Ends
  1107. playerTable = db.GetMapPlayerTable(p.playerID)
  1108. updateScouts = []int32{}
  1109. )
  1110. // 处理侦察开始队列
  1111. for _, queueID := range starts {
  1112. curScout, found := playerTable.Scouts.GetScout(queueID)
  1113. if !found {
  1114. p.Warn("[scoutUpdateNotice] start fail, queue not found. queueID = %d", queueID)
  1115. continue
  1116. }
  1117. errCode := scout.Service().CheckScoutSuccess(playerTable, queueID, curScout)
  1118. if code.IsFail(errCode) {
  1119. continue
  1120. }
  1121. // 更新侦察结束时间
  1122. curScout.EndTime = data.Const.GetMapScoutTime()
  1123. errCode = mapCall.Scout.ScoutUpdateStatus(queueID, enum.ScoutType_Start, p.playerID, curScout.EndTime)
  1124. if code.IsFail(errCode) {
  1125. p.Warn("[scoutUpdateNotice] start fail, update status fail. queueID = %d", queueID)
  1126. continue
  1127. }
  1128. updateScouts = append(updateScouts, queueID)
  1129. }
  1130. // 处理侦察结束队列
  1131. for _, queueID := range ends {
  1132. curScout, found := playerTable.Scouts.GetScout(queueID)
  1133. if !found {
  1134. p.Warn("[scoutUpdateNotice] end fail, queue not found. queueID = %d", queueID)
  1135. continue
  1136. }
  1137. errCode := scout.Service().CheckScoutSuccess(playerTable, queueID, curScout)
  1138. if code.IsFail(errCode) {
  1139. continue
  1140. }
  1141. // 发送call到目标玩家获取目标玩家的木石粮铁
  1142. mapCall.Player.ScoutSearch(queueID, p.playerID, curScout.TargetPlayerID)
  1143. updateScouts = append(updateScouts, queueID)
  1144. }
  1145. if len(updateScouts) > 0 {
  1146. playerTable.SetChangeData()
  1147. // 通知客户端更新
  1148. if p.isOnline {
  1149. scout.Service().ChangePush(playerTable, updateScouts...)
  1150. }
  1151. }
  1152. }
  1153. // 侦察查询
  1154. func (p *actorPlayer) scoutSearch(req *pb.I32I64) {
  1155. // 获取目标玩家的木石粮铁
  1156. var (
  1157. playerStorageTable = db.GetMapPlayerStorageTable(p.playerID)
  1158. playerTable = db.GetMapPlayerTable(p.playerID)
  1159. )
  1160. // 获取木石粮铁
  1161. assets := playerStorageTable.GetCurrencys(enum.MapScoutItemIDList...)
  1162. // 返回给侦察者
  1163. mapCall.Player.ScoutSearchResult(req.Key, req.Value, p.playerID, playerTable.PlayerName, assets)
  1164. // TODO 判断是否需要通知被侦察玩家
  1165. }
  1166. // 侦察结果
  1167. func (p *actorPlayer) scoutSearchResult(req *pb.ScoutSearchResult) {
  1168. var (
  1169. queueID = req.QueueID
  1170. playerTable = db.GetMapPlayerTable(p.playerID)
  1171. )
  1172. curScout, found := playerTable.Scouts.GetScout(req.QueueID)
  1173. if !found {
  1174. p.Warn("[scoutSearchResult] scout not found. playerID=%d, queueID = %d", p.playerID, req.QueueID)
  1175. return
  1176. }
  1177. // 构建战报
  1178. reportGroup := battle.Service().BuildScoutReportGroup(p.playerID, req.TargetPlayerID, playerTable.LeagueID,
  1179. playerTable.PlayerName, req.TargetPlayerName, curScout.Point.ToProto(), req.Assets, enum.ScoutState_Success)
  1180. // 发送侦察成功战报
  1181. battle.Service().AddReport(p.playerID, reportGroup)
  1182. curScout.Reset()
  1183. playerTable.SetChangeData()
  1184. // 通知客户端队列更新
  1185. if p.isOnline {
  1186. scout.Service().ChangePush(playerTable, queueID)
  1187. }
  1188. }
  1189. func (p *actorPlayer) notifyRebornPush(req *pb.Point) {
  1190. p.Debug("[notifyRebornPush] req = %+v", req)
  1191. playerTable := db.GetMapPlayerTable(p.playerID)
  1192. if p.isOnline {
  1193. sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_Reborn, &pb.RebornPush{
  1194. Point: &pb.Point{
  1195. X: req.X,
  1196. Y: req.Y,
  1197. },
  1198. })
  1199. return
  1200. }
  1201. // 玩家不在线,保存一下,玩家登录时推送
  1202. playerTable.RebornInfo = &dbMapPlayer.RebornInfo{
  1203. Point: types.NewPoint(req.X, req.Y),
  1204. }
  1205. playerTable.Save2Queue()
  1206. }