player_map.go 40 KB

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