player_map.go 43 KB

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