player_map.go 41 KB

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