league_map.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. package mapLeague
  2. import (
  3. "f1-game/internal/code"
  4. "f1-game/internal/constant"
  5. "f1-game/internal/data"
  6. "f1-game/internal/enum"
  7. "f1-game/internal/event"
  8. nameEvent "f1-game/internal/name/event"
  9. nameLocal "f1-game/internal/name/local"
  10. nameRemote "f1-game/internal/name/remote"
  11. nameRoute "f1-game/internal/name/route"
  12. "f1-game/internal/pb"
  13. "f1-game/internal/sessions"
  14. mapCall "f1-game/nodes/map/internal/call"
  15. "f1-game/nodes/map/internal/db"
  16. leagueMail "f1-game/nodes/map/league/mail"
  17. ctime "github.com/cherry-game/cherry/extend/time"
  18. cfacade "github.com/cherry-game/cherry/facade"
  19. cproto "github.com/cherry-game/cherry/net/proto"
  20. )
  21. func (p *actorLeague) initMap() {
  22. p.Local().Register(nameLocal.MapLeague_Build, p.build)
  23. p.Local().Register(nameLocal.MapLeague_BuildUpgrade, p.buildUpgrade)
  24. p.Local().Register(nameLocal.MapLeague_BuildDiscard, p.buildDiscard)
  25. p.Local().Register(nameLocal.MapLeague_DiscardCancel, p.discardCancel)
  26. p.Remote().Register(nameRemote.MapLeague_BuildUpdate, p.buildUpdate)
  27. p.EventRegister(nameEvent.League_BuildFinish, p.buildFinish)
  28. p.EventRegister(nameEvent.League_PointDestroy, p.pointDestroy)
  29. }
  30. func (p *actorLeague) build(session *cproto.Session, req *pb.MapBuildRequest) {
  31. p.Debug("[build] req = %v", req)
  32. opPlayerID := sessions.GetPlayerID(session)
  33. leagueMemberTable, found := db.GetMapLeagueMemberTable(p.leagueID)
  34. if !found {
  35. p.ResponseCode(session, code.LeagueMembersEmpty)
  36. return
  37. }
  38. // 权限检查 需要同盟建设权限
  39. ok := leagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction)
  40. if !ok {
  41. p.ResponseCode(session, code.LeaguePermissionDenied)
  42. return
  43. }
  44. row, ok := data.MapBuild.GetByConfigID(req.ConfigID)
  45. if !ok {
  46. p.ResponseCode(session, code.ConfigNotFound_MapBuild)
  47. return
  48. }
  49. // 不是联盟建筑
  50. if row.BuildType != enum.BuildType_League {
  51. p.ResponseCode(session, code.MapBuild_NotLeagueBuild)
  52. return
  53. }
  54. buildCount := p.leagueTable.Builds.GetBuildCount(req.ConfigID)
  55. // TODO 建造上限需要计算
  56. if buildCount >= row.InitBuildLimit {
  57. p.ResponseCode(session, code.MapBuild_NumLimit)
  58. return
  59. }
  60. // 资源不足
  61. if len(row.BuildCost) > 0 && !p.isEnough(row.BuildCost) {
  62. p.ResponseCode(session, code.ItemNotEnough)
  63. return
  64. }
  65. // 计算建造时间
  66. buildTime := row.BuildTime
  67. // 首次建造
  68. if buildCount == 0 {
  69. if time, ok := data.Const.MapBuildFirstTimeElapsed[req.ConfigID]; ok {
  70. buildTime = time
  71. }
  72. }
  73. level := int32(1)
  74. if req.ConfigID == constant.MapBuild_LeaguePoint {
  75. level = p.leagueTable.LeagueInfo.Level
  76. }
  77. arg := pb.BuildLeagueRequest{
  78. ConfigID: req.ConfigID,
  79. LeagueID: p.leagueID,
  80. Level: level,
  81. X: req.Point.X,
  82. Y: req.Point.Y,
  83. BuildEndTime: ctime.Now().ToMillisecond() + buildTime*ctime.MillisecondsPerSecond,
  84. }
  85. rsp, errCode := mapCall.Logic.BuildLeague(&arg)
  86. if code.IsFail(errCode) {
  87. p.Debug("build fail: errCode = %d", errCode)
  88. p.ResponseCode(session, errCode)
  89. return
  90. }
  91. // 扣除资源
  92. if len(row.BuildCost) > 0 {
  93. p.subAssets(row.BuildCost)
  94. }
  95. newObjectID, removeObjectID := rsp.Key, rsp.Value
  96. newBuild := p.leagueTable.Builds.AddBuild(req.ConfigID, newObjectID, req.Point.X, req.Point.Y, arg.BuildEndTime)
  97. buildsUpdatePushRsp := &pb.MapObjectsUpdate{}
  98. if removeObjectID != 0 {
  99. p.leagueTable.Builds.RemoveBuild(removeObjectID)
  100. // 给所有联盟成员推送建筑更新
  101. buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{
  102. IsDelete: true,
  103. ObjectID: removeObjectID,
  104. ObjectType: int32(enum.ObjectType_Build),
  105. })
  106. }
  107. p.leagueTable.Save2Queue()
  108. p.ResponseCode(session, code.OK)
  109. p.PostEvent(event.NewLeagueBuild(p.leagueID, req.ConfigID, req.Point))
  110. // 给所有联盟成员推送建筑更新
  111. buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{
  112. ObjectID: newObjectID,
  113. ConfigID: newBuild.ConfigID,
  114. ObjectType: int32(enum.ObjectType_Build),
  115. Point: newBuild.Point.ToProto(),
  116. Time: newBuild.BuildEndTime,
  117. })
  118. p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, buildsUpdatePushRsp)
  119. }
  120. // 联盟建筑升级
  121. func (p *actorLeague) buildUpgrade(session *cproto.Session, req *pb.I64) {
  122. opPlayerID := sessions.GetPlayerID(session)
  123. leagueMemberTable, found := db.GetMapLeagueMemberTable(p.leagueID)
  124. if !found {
  125. p.ResponseCode(session, code.LeagueMembersEmpty)
  126. return
  127. }
  128. // 权限检查 需要同盟建设权限
  129. ok := leagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction)
  130. if !ok {
  131. p.ResponseCode(session, code.LeaguePermissionDenied)
  132. return
  133. }
  134. build, found := p.leagueTable.Builds.GetBuild(req.Value)
  135. if !found {
  136. p.ResponseCode(session, code.MapBuild_NotFound)
  137. return
  138. }
  139. // 联盟驻地不支持手动升级 跟随联盟等级
  140. if build.ConfigID == constant.MapBuild_LeaguePoint {
  141. p.ResponseCode(session, code.MapBuild_NotUpgrade)
  142. return
  143. }
  144. if build.IsBuilding() {
  145. p.ResponseCode(session, code.MapBuild_IsBuilding)
  146. return
  147. }
  148. if build.IsUpgrading() {
  149. p.ResponseCode(session, code.MapBuild_IsUpgrading)
  150. return
  151. }
  152. if build.DiscardTime > 0 {
  153. p.ResponseCode(session, code.MapBuild_AlreadyDiscarding)
  154. return
  155. }
  156. curMapBuildUpgradeRow, found := data.MapBuildUpgrade.GetByConfigIDLevel(build.ConfigID, build.Level)
  157. if !found {
  158. p.ResponseCode(session, code.MapBuildUpgrade_NotFound)
  159. return
  160. }
  161. // 判断下一等级的配置是否存在
  162. _, found = data.MapBuildUpgrade.GetByConfigIDLevel(build.ConfigID, build.Level+1)
  163. if !found {
  164. p.ResponseCode(session, code.ConfigNotFound_MapBuildUpgrade)
  165. return
  166. }
  167. // 升级消耗不存在
  168. if curMapBuildUpgradeRow.UpgradeCost.IsEmpty() {
  169. p.ResponseCode(session, code.MapBuildUpgradeCost_NotExist)
  170. return
  171. }
  172. if !p.isEnough(curMapBuildUpgradeRow.UpgradeCost) {
  173. p.ResponseCode(session, code.ItemNotEnough)
  174. return
  175. }
  176. // 升级结束时间戳
  177. upgradeEndTime := ctime.Now().ToMillisecond() + curMapBuildUpgradeRow.UpgradeTime*ctime.MillisecondsPerSecond
  178. arg := &pb.BuildUpgradeRequest{
  179. ObjectID: build.ObjectID,
  180. ConfigID: build.ConfigID,
  181. LeagueID: p.leagueID,
  182. Level: build.Level,
  183. UpgradeEndTime: upgradeEndTime,
  184. }
  185. errCode := mapCall.Logic.BuildUpgrade(arg)
  186. if code.IsFail(errCode) {
  187. p.ResponseCode(session, errCode)
  188. return
  189. }
  190. // 扣除资源
  191. p.subAssets(curMapBuildUpgradeRow.UpgradeCost)
  192. // TODO 是否单独字段保存升级结束时间戳 现在先放建造结束时间
  193. build.UpgradeEndTime = upgradeEndTime
  194. p.leagueTable.Save2Queue()
  195. p.ResponseCode(session, code.OK)
  196. // 给所有联盟成员推送建筑更新
  197. buildsUpdatePushRsp := &pb.MapObjectsUpdate{}
  198. buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{
  199. ObjectID: build.ObjectID,
  200. ConfigID: build.ConfigID,
  201. ObjectType: int32(enum.ObjectType_Build),
  202. Point: build.Point.ToProto(),
  203. Time: build.BuildEndTime,
  204. })
  205. p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, buildsUpdatePushRsp)
  206. }
  207. // buildDiscard 摧毁联盟建筑
  208. func (p *actorLeague) buildDiscard(session *cproto.Session, req *pb.I64) {
  209. objectID := req.Value
  210. p.Debug("[buildDiscard] objectID = %d", objectID)
  211. build, found := p.leagueTable.Builds.GetBuild(objectID)
  212. if !found {
  213. p.ResponseCode(session, code.MapLeague_BuildNotFound)
  214. return
  215. }
  216. mapBuildRow, found := data.MapBuild.GetByConfigID(build.ConfigID)
  217. if !found {
  218. p.ResponseCode(session, code.ConfigNotFound_MapBuild)
  219. return
  220. }
  221. // 当前建筑不可摧毁
  222. if !mapBuildRow.Discardable {
  223. p.ResponseCode(session, code.MapLeague_NotCanDiscard)
  224. return
  225. }
  226. // TODO 建筑建造中是否能摧毁
  227. // 已经在摧毁中
  228. if build.DiscardTime > 0 {
  229. p.ResponseCode(session, code.MapBuild_AlreadyDiscarding)
  230. return
  231. }
  232. opPlayerID := sessions.GetPlayerID(session)
  233. mapLeagueMemberTable, _ := db.GetMapLeagueMemberTable(p.leagueID)
  234. // 检查权限
  235. if !mapLeagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) {
  236. p.ResponseCode(session, code.LeaguePermissionDenied)
  237. return
  238. }
  239. discardTime, errCode := mapCall.Logic.BuildDiscard(p.leagueID, objectID)
  240. if code.IsFail(errCode) {
  241. p.ResponseCode(session, errCode)
  242. return
  243. }
  244. build.DiscardTime = discardTime
  245. p.leagueTable.Save2Queue()
  246. p.ResponseCode(session, code.OK)
  247. // 给所有联盟成员推送建筑更新
  248. p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{
  249. List: []*pb.MapObjectUpdate{
  250. {
  251. IsDelete: true,
  252. ObjectID: objectID,
  253. ConfigID: build.ConfigID,
  254. ObjectType: int32(enum.ObjectType_Build),
  255. Point: build.Point.ToProto(),
  256. Time: discardTime,
  257. },
  258. },
  259. })
  260. }
  261. // buildDiscard 摧毁联盟建筑
  262. func (p *actorLeague) discardCancel(session *cproto.Session, req *pb.I64I32) {
  263. var (
  264. objectID = req.Key
  265. objectType = enum.ObjectType(req.Value)
  266. )
  267. p.Debug("[discardCancel] objectID = %d, objectType = %s", objectID, enum.GetObjectTypeName(objectType))
  268. opPlayerID := sessions.GetPlayerID(session)
  269. mapLeagueMemberTable, _ := db.GetMapLeagueMemberTable(p.leagueID)
  270. // 检查权限
  271. if !mapLeagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) {
  272. p.ResponseCode(session, code.LeaguePermissionDenied)
  273. return
  274. }
  275. errCode := mapCall.Logic.DiscardCancelLeague(p.leagueID, objectID, int32(objectType))
  276. if code.IsFail(errCode) {
  277. p.ResponseCode(session, errCode)
  278. return
  279. }
  280. switch objectType {
  281. case enum.ObjectType_Build:
  282. build, found := p.leagueTable.Builds.GetBuild(objectID)
  283. if !found {
  284. p.ResponseCode(session, code.MapLeague_BuildNotFound)
  285. return
  286. }
  287. build.DiscardTime = 0
  288. p.leagueTable.Save2Queue()
  289. // 给所有联盟成员推送建筑更新
  290. p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{
  291. List: []*pb.MapObjectUpdate{
  292. {
  293. ObjectID: objectID,
  294. ConfigID: build.ConfigID,
  295. ObjectType: int32(enum.ObjectType_Build),
  296. Point: build.Point.ToProto(),
  297. Time: 0,
  298. },
  299. },
  300. })
  301. }
  302. p.ResponseCode(session, code.OK)
  303. }
  304. func (p *actorLeague) buildUpdate(req *pb.BuildUpdate) {
  305. p.Debug("[buildUpdate] req = %+v", req)
  306. var (
  307. point = &pb.Point{
  308. X: req.X,
  309. Y: req.Y,
  310. }
  311. mapObjectUpdate = &pb.MapObjectUpdate{
  312. ObjectID: req.ObjectID,
  313. ConfigID: req.ConfigID,
  314. ObjectType: int32(enum.ObjectType_Build),
  315. Point: point,
  316. }
  317. )
  318. if req.IsAdd {
  319. // 占领获取了建筑,不用设置建造时间
  320. p.leagueTable.Builds.AddBuild(req.ConfigID, req.ObjectID, req.X, req.Y, 0)
  321. } else {
  322. p.leagueTable.Builds.RemoveBuild(req.ObjectID)
  323. mapObjectUpdate.IsDelete = true
  324. // 给所有联盟成员推送邮件
  325. // TODO 先用系统邮件通知,等后面有了联盟系统邮件再改
  326. leagueMail.Service().SendAllMemberMail(p.leagueID, constant.MailID_LeagueBuildDiscard, nil, req.ConfigID, point)
  327. }
  328. p.leagueTable.Save2Queue()
  329. // 给所有联盟成员推送建筑更新
  330. p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{
  331. List: []*pb.MapObjectUpdate{mapObjectUpdate},
  332. })
  333. }
  334. // 联盟建筑建造/升级完成事件处理
  335. func (p *actorLeague) buildFinish(eventData cfacade.IEventData) {
  336. p.Debug("[buildFinish] leagueID:%d, eventData=%+v", p.leagueID, eventData)
  337. evt, ok := eventData.(*event.LeagueBuildFinish)
  338. if !ok {
  339. p.Warn("[buildFinish] eventData error. leagueID:%d", p.leagueID)
  340. return
  341. }
  342. var (
  343. req = evt.Key()
  344. isUp = evt.Value()
  345. objectID = req.Key
  346. level = req.Value
  347. )
  348. build, ok := p.leagueTable.Builds.GetBuild(objectID)
  349. if !ok {
  350. p.Warn("[buildFinish] build not found. leagueID:%d, objectID:%d", p.leagueID, objectID)
  351. return
  352. }
  353. build.Level = level
  354. p.leagueTable.Save2Queue()
  355. if !isUp {
  356. // 建造完成的时候推送全员邮件
  357. // TODO 先用系统邮件通知,等后面有了联盟系统邮件再改
  358. leagueMail.Service().SendAllMemberMail(p.leagueID, constant.MailID_LeagueBuild, nil, build.ConfigID, build.Point)
  359. }
  360. }
  361. // 联盟建筑建造/升级完成事件处理
  362. func (p *actorLeague) pointDestroy(eventData cfacade.IEventData) {
  363. evt, ok := eventData.(*event.LeaguePointDestroy)
  364. if !ok {
  365. p.Warn("[leaguePointDestroy] eventData error. leagueID:%d", p.leagueID)
  366. return
  367. }
  368. p.Debug("[leaguePointDestroy] leagueID = %d, objectID = %d", p.leagueID, evt.ObjectID())
  369. // 通知所有联盟成员再起
  370. for _, re := range p.leagueTable.Residences {
  371. mapCall.Player.AutoReborn(re.PlayerID)
  372. }
  373. // 清空驻地
  374. p.leagueTable.Residences.Clear()
  375. // 删除驻地
  376. p.leagueTable.Builds.RemoveBuild(evt.ObjectID())
  377. p.leagueTable.Save2Queue()
  378. // 通知在线成员更新驻地信息
  379. p.pushToMembers(nameRoute.PushMapLeague_Residence, &pb.LeagueResidenceList{})
  380. }