package conscript import ( actorRemote "f1-game/internal/actor_remote" capp "f1-game/internal/cherry_app" "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" "f1-game/internal/event" "f1-game/internal/extend/math" facade "f1-game/internal/facade" nameRoute "f1-game/internal/name/route" "f1-game/internal/sessions" ao "f1-game/nodes/game/player/asset/origin" "f1-game/nodes/map/internal/db" mapFacade "f1-game/nodes/map/internal/facade" "f1-game/nodes/map/player/storage" ctime "github.com/cherry-game/cherry/extend/time" clog "github.com/cherry-game/cherry/logger" cproto "github.com/cherry-game/cherry/net/proto" ) var srv = &service{} type service struct { facade.PlayerServiceBase[*db.MapPlayerTable] } func Service() *service { return srv } func (p *service) OnLogin(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) { // 当前没有征兵/升级任务 if mapPlayerTable.Conscripts.IsNotConscriptAction() { return } // 计算登录时间和登出的时间差 var ( nowMilliSecond = ctime.Now().ToMillisecond() lastLogoutTime = mapPlayerTable.Stats.LastLogoutTime diffSecond = (nowMilliSecond - lastLogoutTime) / ctime.MillisecondsPerSecond ) // 结算离线征兵/兵种升级 p.handleConscriptSettle(mapPlayerTable, int32(diffSecond)) } func (p *service) OnLogout(mapPlayerTable *db.MapPlayerTable) { mapPlayerTable.Stats.LastLogoutTime = ctime.Now().ToMillisecond() mapPlayerTable.Save2Queue() } // func (p *service) OnReset(mapPlayerTable *db.PlayerTable, time *ctime.CherryTime, byLogin bool) { // } // 推送征兵信息 func (p *service) Push(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) { resp := mapPlayerTable.Conscripts.ToProto() sessions.PushWithSession(session, nameRoute.PushMapPlayer_Conscript, &resp) } // 每秒执行征兵结算 func (p *service) ConscriptSettle(playerID, nowSecond int64) { mapPlayerTable := db.GetMapPlayerTable(playerID) if mapPlayerTable == nil { clog.Warnf("conscript settle player not found. playerID:%d", playerID) return } // 1s 计算 p.handleConscriptSettle(mapPlayerTable, 1) } func (p *service) handleConscriptSettle(mapPlayerTable *db.MapPlayerTable, second int32) { // 当前没有征兵/升级任务 if mapPlayerTable.Conscripts.IsNotConscriptAction() { return } var ( conscripts = mapPlayerTable.Conscripts save = false ) // 当前为征兵 if conscripts.IsConscript() { // 执行1s征兵结算 save = p.doConscriptSettle(mapPlayerTable, second) // 如果当前征兵已完成 且 开启自动征兵 则执行下一次征兵 if conscripts.Conscript.IsConscriptFinish() && conscripts.Conscript.AutoConscript { if p.AutoConscript(mapPlayerTable, conscripts.Conscript.ArmID) { save = true } } } // 当前为士兵升级 if conscripts.IsConscriptUp() { save = p.doConscriptUpSettle(mapPlayerTable, second) } // 保存征兵数据 if save { mapPlayerTable.Save2Queue() // 通知客户端 session, found := sessions.GetSession(mapPlayerTable.PlayerID) if found { p.Push(mapPlayerTable, session) } } } // TODO 后面改成 执行征兵结算 func (p *service) doConscriptSettle(mapPlayerTable *db.MapPlayerTable, second int32) bool { var ( playerID = mapPlayerTable.PlayerID armID = mapPlayerTable.Conscripts.Conscript.ArmID num = int64(mapPlayerTable.Conscripts.Conscript.ConscriptRemain()) ) if num <= 0 || armID <= 0 { return false } armLevelRow, found := data.ArmLevel.GetByID(armID) if !found { clog.Warnf("[doConscriptSettle] arm level config not found. armID:%d", armID) return false } var ( // 预备兵上限 armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit) // 获取征兵/升级的士兵当前数量 curNum = p.GetCurTroopNum(playerID) ) // 判断如果数量已达上限 则更新时间 不结算 if curNum >= armLimit { return false } // 获得兵力= 结算次数 * 结算时间 * 单次兵力 addNum := p.calConscriptNumSecond(mapPlayerTable, second*armLevelRow.ConscriptNumSecond) if addNum <= 0 { clog.Warnf("[doConscriptSettle] calConscriptNumSecond num <= 0. playerID = %d", playerID) return false } if addNum >= num { addNum = num } // 修正添加数量 if curNum+addNum > armLimit { addNum = armLimit - curNum } mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID) conscript := mapPlayerStorageTable.Storage.CurrencyMap.GetEntity(armID) conscript.Num += addNum mapPlayerStorageTable.Save2Queue() clog.Debugf("[doConscriptSettle] playerID = %d, armID = %d, addNum = %d", playerID, armID, addNum) // 推送兵力变更 storage.Service().ChangePush(playerID, armID) progress := int32(addNum) // 增加征兵进度 mapPlayerTable.Conscripts.AddConscriptProgress(progress) // 当前征兵/升级完成 if mapPlayerTable.Conscripts.Conscript.IsConscriptFinish() { // 提交事件 capp.PostEvent(event.NewConscriptTroopSettle(playerID, armID, mapPlayerTable.Conscripts.Conscript.Total)) // 系统消息 actorRemote.GamePlayer.GamePlayerCallSystemMsg(mapPlayerTable.GameNodeID, playerID, enum.ChatMsgType_conscript, nil, nil, armID, mapPlayerTable.Conscripts.Conscript.Total) // 如果没有设置自动补兵 则重置 if !mapPlayerTable.Conscripts.Conscript.AutoConscript { mapPlayerTable.Conscripts.ResetConscript() } else { mapPlayerTable.Conscripts.Conscript.Total = 0 mapPlayerTable.Conscripts.Conscript.Progress = 0 } } return true } // 执行士兵升级结算 func (p *service) doConscriptUpSettle(mapPlayerTable *db.MapPlayerTable, second int32) bool { var ( playerID = mapPlayerTable.PlayerID upArmID = mapPlayerTable.Conscripts.ConscriptUp.UpArmID remain = int64(mapPlayerTable.Conscripts.ConscriptUp.ConscriptUpRemain()) ) if upArmID <= 0 || remain <= 0 { return false } upArmLevelRow, found := data.ArmLevel.GetByID(upArmID) if !found { clog.Warnf("[doConscriptUpSettle] up arm level config not found. playerID:%d,upArmID:%d", playerID, upArmID) return false } var ( // 预备兵上限 armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit) // 获取征兵/升级的士兵当前数量 curNum = p.GetCurTroopNum(playerID) ) // 判断如果数量已达上限 则更新时间 不结算 if curNum >= armLimit { return false } // 获得兵力= 结算次数 * 结算时间 * 单次兵力 addNum := p.calConscriptNumSecond(mapPlayerTable, second*upArmLevelRow.ConscriptNumSecond) if addNum <= 0 { clog.Warnf("[doConscriptUpSettle] calConscriptNumSecond num <=0. playerID:%d", mapPlayerTable.PlayerID) return false } if addNum >= remain { addNum = remain } // 修正添加数量 addNum = math.Min(addNum, armLimit-curNum) mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID) conscript := mapPlayerStorageTable.Storage.CurrencyMap.GetEntity(upArmID) conscript.Num += addNum mapPlayerStorageTable.Save2Queue() clog.Debugf("[doConscriptUpSettle] playerID = %d, upArmID = %d, addNum = %d", playerID, upArmID, addNum) // 推送兵力变更 storage.Service().ChangePush(playerID, upArmID) progress := int32(addNum) // 增加征兵进度 mapPlayerTable.Conscripts.AddConscriptUpProgress(progress) // 当前征兵/升级完成 if mapPlayerTable.Conscripts.ConscriptUp.IsConscriptUpFinish() { // 提交事件 capp.PostEvent(event.NewConscriptTroopSettle(playerID, upArmID, mapPlayerTable.Conscripts.ConscriptUp.Total)) actorRemote.GamePlayer.GamePlayerCallSystemMsg(mapPlayerTable.GameNodeID, playerID, enum.ChatMsgType_conscriptUp, nil, nil, upArmID, mapPlayerTable.Conscripts.ConscriptUp.Total) mapPlayerTable.Conscripts.ResetConscriptUp() } return true } // 计算征兵的数量 func (p *service) calConscriptNumSecond(mapPlayerTable *db.MapPlayerTable, oneSecondNum int32) int64 { addRatio := float64(mapPlayerTable.Facilities.Attrs.Get(enum.AttrConscriptSpeed)) / constant.RatioBase singleAdd := math.Round[float64, int64]((1 + addRatio) * float64(oneSecondNum)) return singleAdd } // 执行自动征兵 默认都是征兵 没有升级 func (p *service) AutoConscript(mapPlayerTable *db.MapPlayerTable, armID int32) bool { playerID := mapPlayerTable.PlayerID armLevelRow, found := data.ArmLevel.GetByID(armID) if !found { clog.Warnf("auto conscript arm level config not found. armID:%d", armID) return false } var ( // 预备兵上限 armLimit = mapPlayerTable.Facilities.Attrs.Get(enum.AttrArmsLimit) // 获取征兵/升级的士兵当前数量 curNum = p.GetCurTroopNum(playerID) + int64(mapPlayerTable.Conscripts.Conscript.ConscriptRemain()) // 征兵数量 conscriptNum = armLimit - curNum ) // 当前数量已达上限 跳过 if conscriptNum <= 0 { return false } // 获取当前征兵消耗 for _, item := range armLevelRow.ConscriptCostItems { // 获取当前资源数量 curNum := mapFacade.Storage.Get(playerID, item.ID) if curNum <= 0 { return false } // 当前道具可征兵数量 diffNum := curNum / item.Num if diffNum <= 0 { return false } conscriptNum = math.Min(conscriptNum, diffNum) } if conscriptNum <= 0 { return false } // 计算征兵消耗 costs := armLevelRow.CalConscriptAssets(conscriptNum) // 扣除资源 _, errCode := mapFacade.Storage.AssetSubs(playerID, costs, ao.ConscriptCost) if code.IsFail(errCode) { return false } // 开始征兵 mapPlayerTable.Conscripts.StartConscript(armID, int32(conscriptNum)) return true } // 获取当前预备兵数量 func (p *service) GetCurTroopNum(playerID int64) int64 { total := int64(0) for _, armLevelRow := range data.ArmLevel.List() { // TODO 暂时调用game player的service等背包迁移到地图 获取当前资源数量 total += mapFacade.Storage.Get(playerID, armLevelRow.ID) } return total }