package mapLeague import ( "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" "f1-game/internal/event" nameEvent "f1-game/internal/name/event" nameLocal "f1-game/internal/name/local" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" mapCall "f1-game/nodes/map/internal/call" "f1-game/nodes/map/internal/db" leagueMail "f1-game/nodes/map/league/mail" ctime "github.com/cherry-game/cherry/extend/time" cfacade "github.com/cherry-game/cherry/facade" cproto "github.com/cherry-game/cherry/net/proto" ) func (p *actorLeague) initMap() { p.Local().Register(nameLocal.MapLeague_Build, p.build) p.Local().Register(nameLocal.MapLeague_BuildUpgrade, p.buildUpgrade) p.Local().Register(nameLocal.MapLeague_BuildDiscard, p.buildDiscard) p.Local().Register(nameLocal.MapLeague_DiscardCancel, p.discardCancel) p.Remote().Register(nameRemote.MapLeague_BuildUpdate, p.buildUpdate) p.EventRegister(nameEvent.League_BuildFinish, p.buildFinish) p.EventRegister(nameEvent.League_PointDestroy, p.pointDestroy) } func (p *actorLeague) build(session *cproto.Session, req *pb.MapBuildRequest) { p.Debug("[build] req = %v", req) opPlayerID := sessions.GetPlayerID(session) leagueMemberTable, found := db.GetMapLeagueMemberTable(p.leagueID) if !found { p.ResponseCode(session, code.LeagueMembersEmpty) return } // 权限检查 需要同盟建设权限 ok := leagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) if !ok { p.ResponseCode(session, code.LeaguePermissionDenied) return } row, ok := data.MapBuild.GetByConfigID(req.ConfigID) if !ok { p.ResponseCode(session, code.ConfigNotFound_MapBuild) return } // 不是联盟建筑 if row.BuildType != enum.BuildType_League { p.ResponseCode(session, code.MapBuild_NotLeagueBuild) return } buildCount := p.leagueTable.Builds.GetBuildCount(req.ConfigID) // TODO 建造上限需要计算 if buildCount >= row.InitBuildLimit { p.ResponseCode(session, code.MapBuild_NumLimit) return } // 资源不足 if len(row.BuildCost) > 0 && !p.isEnough(row.BuildCost) { p.ResponseCode(session, code.ItemNotEnough) return } // 计算建造时间 buildTime := row.BuildTime // 首次建造 if buildCount == 0 { if time, ok := data.Const.MapBuildFirstTimeElapsed[req.ConfigID]; ok { buildTime = time } } level := int32(1) if req.ConfigID == constant.MapBuild_LeaguePoint { level = p.leagueTable.LeagueInfo.Level } arg := pb.BuildLeagueRequest{ ConfigID: req.ConfigID, LeagueID: p.leagueID, Level: level, X: req.Point.X, Y: req.Point.Y, BuildEndTime: ctime.Now().ToMillisecond() + buildTime*ctime.MillisecondsPerSecond, } rsp, errCode := mapCall.Logic.BuildLeague(&arg) if code.IsFail(errCode) { p.Debug("build fail: errCode = %d", errCode) p.ResponseCode(session, errCode) return } // 扣除资源 if len(row.BuildCost) > 0 { p.subAssets(row.BuildCost) } newObjectID, removeObjectID := rsp.Key, rsp.Value newBuild := p.leagueTable.Builds.AddBuild(req.ConfigID, newObjectID, req.Point.X, req.Point.Y, arg.BuildEndTime) buildsUpdatePushRsp := &pb.MapObjectsUpdate{} if removeObjectID != 0 { p.leagueTable.Builds.RemoveBuild(removeObjectID) // 给所有联盟成员推送建筑更新 buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{ IsDelete: true, ObjectID: removeObjectID, ObjectType: int32(enum.ObjectType_Build), }) } p.leagueTable.Save2Queue() p.ResponseCode(session, code.OK) p.PostEvent(event.NewLeagueBuild(p.leagueID, req.ConfigID, req.Point)) // 给所有联盟成员推送建筑更新 buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{ ObjectID: newObjectID, ConfigID: newBuild.ConfigID, ObjectType: int32(enum.ObjectType_Build), Point: newBuild.Point.ToProto(), Time: newBuild.BuildEndTime, }) p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, buildsUpdatePushRsp) } // 联盟建筑升级 func (p *actorLeague) buildUpgrade(session *cproto.Session, req *pb.I64) { opPlayerID := sessions.GetPlayerID(session) leagueMemberTable, found := db.GetMapLeagueMemberTable(p.leagueID) if !found { p.ResponseCode(session, code.LeagueMembersEmpty) return } // 权限检查 需要同盟建设权限 ok := leagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) if !ok { p.ResponseCode(session, code.LeaguePermissionDenied) return } build, found := p.leagueTable.Builds.GetBuild(req.Value) if !found { p.ResponseCode(session, code.MapBuild_NotFound) return } // 联盟驻地不支持手动升级 跟随联盟等级 if build.ConfigID == constant.MapBuild_LeaguePoint { p.ResponseCode(session, code.MapBuild_NotUpgrade) return } if build.IsBuilding() { p.ResponseCode(session, code.MapBuild_IsBuilding) return } if build.IsUpgrading() { p.ResponseCode(session, code.MapBuild_IsUpgrading) return } if build.DiscardTime > 0 { p.ResponseCode(session, code.MapBuild_AlreadyDiscarding) return } curMapBuildUpgradeRow, found := data.MapBuildUpgrade.GetByConfigIDLevel(build.ConfigID, build.Level) if !found { p.ResponseCode(session, code.MapBuildUpgrade_NotFound) return } // 判断下一等级的配置是否存在 _, found = data.MapBuildUpgrade.GetByConfigIDLevel(build.ConfigID, build.Level+1) if !found { p.ResponseCode(session, code.ConfigNotFound_MapBuildUpgrade) return } // 升级消耗不存在 if curMapBuildUpgradeRow.UpgradeCost.IsEmpty() { p.ResponseCode(session, code.MapBuildUpgradeCost_NotExist) return } if !p.isEnough(curMapBuildUpgradeRow.UpgradeCost) { p.ResponseCode(session, code.ItemNotEnough) return } // 升级结束时间戳 upgradeEndTime := ctime.Now().ToMillisecond() + curMapBuildUpgradeRow.UpgradeTime*ctime.MillisecondsPerSecond arg := &pb.BuildUpgradeRequest{ ObjectID: build.ObjectID, ConfigID: build.ConfigID, LeagueID: p.leagueID, Level: build.Level, UpgradeEndTime: upgradeEndTime, } errCode := mapCall.Logic.BuildUpgrade(arg) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } // 扣除资源 p.subAssets(curMapBuildUpgradeRow.UpgradeCost) // TODO 是否单独字段保存升级结束时间戳 现在先放建造结束时间 build.UpgradeEndTime = upgradeEndTime p.leagueTable.Save2Queue() p.ResponseCode(session, code.OK) // 给所有联盟成员推送建筑更新 buildsUpdatePushRsp := &pb.MapObjectsUpdate{} buildsUpdatePushRsp.List = append(buildsUpdatePushRsp.List, &pb.MapObjectUpdate{ ObjectID: build.ObjectID, ConfigID: build.ConfigID, ObjectType: int32(enum.ObjectType_Build), Point: build.Point.ToProto(), Time: build.BuildEndTime, }) p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, buildsUpdatePushRsp) } // buildDiscard 摧毁联盟建筑 func (p *actorLeague) buildDiscard(session *cproto.Session, req *pb.I64) { objectID := req.Value p.Debug("[buildDiscard] objectID = %d", objectID) build, found := p.leagueTable.Builds.GetBuild(objectID) if !found { p.ResponseCode(session, code.MapLeague_BuildNotFound) return } mapBuildRow, found := data.MapBuild.GetByConfigID(build.ConfigID) if !found { p.ResponseCode(session, code.ConfigNotFound_MapBuild) return } // 当前建筑不可摧毁 if !mapBuildRow.Discardable { p.ResponseCode(session, code.MapLeague_NotCanDiscard) return } // TODO 建筑建造中是否能摧毁 // 已经在摧毁中 if build.DiscardTime > 0 { p.ResponseCode(session, code.MapBuild_AlreadyDiscarding) return } opPlayerID := sessions.GetPlayerID(session) mapLeagueMemberTable, _ := db.GetMapLeagueMemberTable(p.leagueID) // 检查权限 if !mapLeagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) { p.ResponseCode(session, code.LeaguePermissionDenied) return } discardTime, errCode := mapCall.Logic.BuildDiscard(p.leagueID, objectID) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } build.DiscardTime = discardTime p.leagueTable.Save2Queue() p.ResponseCode(session, code.OK) // 给所有联盟成员推送建筑更新 p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{ List: []*pb.MapObjectUpdate{ { IsDelete: true, ObjectID: objectID, ConfigID: build.ConfigID, ObjectType: int32(enum.ObjectType_Build), Point: build.Point.ToProto(), Time: discardTime, }, }, }) } // buildDiscard 摧毁联盟建筑 func (p *actorLeague) discardCancel(session *cproto.Session, req *pb.I64I32) { var ( objectID = req.Key objectType = enum.ObjectType(req.Value) ) p.Debug("[discardCancel] objectID = %d, objectType = %s", objectID, enum.GetObjectTypeName(objectType)) opPlayerID := sessions.GetPlayerID(session) mapLeagueMemberTable, _ := db.GetMapLeagueMemberTable(p.leagueID) // 检查权限 if !mapLeagueMemberTable.CheckPermission(opPlayerID, enum.League_Permission_Construction) { p.ResponseCode(session, code.LeaguePermissionDenied) return } errCode := mapCall.Logic.DiscardCancelLeague(p.leagueID, objectID, int32(objectType)) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } switch objectType { case enum.ObjectType_Build: build, found := p.leagueTable.Builds.GetBuild(objectID) if !found { p.ResponseCode(session, code.MapLeague_BuildNotFound) return } build.DiscardTime = 0 p.leagueTable.Save2Queue() // 给所有联盟成员推送建筑更新 p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{ List: []*pb.MapObjectUpdate{ { ObjectID: objectID, ConfigID: build.ConfigID, ObjectType: int32(enum.ObjectType_Build), Point: build.Point.ToProto(), Time: 0, }, }, }) } p.ResponseCode(session, code.OK) } func (p *actorLeague) buildUpdate(req *pb.BuildUpdate) { p.Debug("[buildUpdate] req = %+v", req) var ( point = &pb.Point{ X: req.X, Y: req.Y, } mapObjectUpdate = &pb.MapObjectUpdate{ ObjectID: req.ObjectID, ConfigID: req.ConfigID, ObjectType: int32(enum.ObjectType_Build), Point: point, } ) if req.IsAdd { // 占领获取了建筑,不用设置建造时间 p.leagueTable.Builds.AddBuild(req.ConfigID, req.ObjectID, req.X, req.Y, 0) } else { p.leagueTable.Builds.RemoveBuild(req.ObjectID) mapObjectUpdate.IsDelete = true // 给所有联盟成员推送邮件 // TODO 先用系统邮件通知,等后面有了联盟系统邮件再改 leagueMail.Service().SendAllMemberMail(p.leagueID, constant.MailID_LeagueBuildDiscard, nil, req.ConfigID, point) } p.leagueTable.Save2Queue() // 给所有联盟成员推送建筑更新 p.pushToMembers(nameRoute.PushMapLeague_BuildUpdate, &pb.MapObjectsUpdate{ List: []*pb.MapObjectUpdate{mapObjectUpdate}, }) } // 联盟建筑建造/升级完成事件处理 func (p *actorLeague) buildFinish(eventData cfacade.IEventData) { p.Debug("[buildFinish] leagueID:%d, eventData=%+v", p.leagueID, eventData) evt, ok := eventData.(*event.LeagueBuildFinish) if !ok { p.Warn("[buildFinish] eventData error. leagueID:%d", p.leagueID) return } var ( req = evt.Key() isUp = evt.Value() objectID = req.Key level = req.Value ) build, ok := p.leagueTable.Builds.GetBuild(objectID) if !ok { p.Warn("[buildFinish] build not found. leagueID:%d, objectID:%d", p.leagueID, objectID) return } build.Level = level p.leagueTable.Save2Queue() if !isUp { // 建造完成的时候推送全员邮件 // TODO 先用系统邮件通知,等后面有了联盟系统邮件再改 leagueMail.Service().SendAllMemberMail(p.leagueID, constant.MailID_LeagueBuild, nil, build.ConfigID, build.Point) } } // 联盟建筑建造/升级完成事件处理 func (p *actorLeague) pointDestroy(eventData cfacade.IEventData) { evt, ok := eventData.(*event.LeaguePointDestroy) if !ok { p.Warn("[leaguePointDestroy] eventData error. leagueID:%d", p.leagueID) return } p.Debug("[leaguePointDestroy] leagueID = %d, objectID = %d", p.leagueID, evt.ObjectID()) // 通知所有联盟成员再起 for _, re := range p.leagueTable.Residences { mapCall.Player.AutoReborn(re.PlayerID) } // 清空驻地 p.leagueTable.Residences.Clear() // 删除驻地 p.leagueTable.Builds.RemoveBuild(evt.ObjectID()) p.leagueTable.Save2Queue() // 通知在线成员更新驻地信息 p.pushToMembers(nameRoute.PushMapLeague_Residence, &pb.LeagueResidenceList{}) }