package mapLogic import ( "f1-game/internal/enum" "f1-game/internal/event" nameEvent "f1-game/internal/name/event" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" "f1-game/internal/types" "f1-game/nodes/map/internal/db" mapTypes "f1-game/nodes/map/internal/types" cfacade "github.com/cherry-game/cherry/facade" clog "github.com/cherry-game/cherry/logger" ) func (p *actor) onInitAOI() { p.Remote().Register(nameRemote.MapLogic_AOIMarkerEnterView, p.aoiMarkerEnterView) p.Remote().Register(nameRemote.MapLogic_AOIMarkerLeaveView, p.aoiMarkerLeaveView) p.Remote().Register(nameRemote.MapLogic_AOIMarkerDespawn, p.aoiMarkerDespawn) p.Remote().Register(nameRemote.MapLogic_AOIMarkerUpdate, p.aoiMarkerUpdate) p.Remote().Register(nameRemote.MapLogic_AOIUpdateMarchState, p.aoiUpdateMarchState) p.Remote().Register(nameRemote.MapLogic_AOIUpdateBattle, p.aoiUpdateBattle) p.Event().Register(nameEvent.Map_WatcherSync, p.mapPlayerSync) p.Event().Register(nameEvent.Map_LeagueSync, p.mapLeagueSync) } // aoiMarkerEnterView aoi marker进入视野回调 func (p *actor) aoiMarkerEnterView(req *mapTypes.AOIMarkerEnterView) { clog.Debugf("[aoiMarkerEnterView] ObjectType = %s, Marker size = %d, Watcher Size = %d", enum.GetObjectTypeName(req.ObjectType), req.Markers.Size(), req.Watchers.Size()) if req.Watchers.Size() == 0 { return } // 军情线 if req.ObjectType == enum.ObjectType_ArmyLine { p.armyLineAoiEnterView(req) return } watchers := req.Watchers.List() mapObjects := &pb.MapObjects{} mapObjects.ObjectList, mapObjects.LegionList = p.buildMapObjectAndLegion(req.ObjectType, req.Markers) // 先推送 marker 对应的玩家数据和联盟数据给 AOI 观察者 p.playerAndLeaguePush(watchers, mapObjects.ObjectList) // 再推送 marker 对象 sessions.PushPlayers(watchers, nameRoute.PushMapPusher_ObjectUpdate, mapObjects) } // aoiMarkerLeaveView aoi marker离开视野回调 func (p *actor) aoiMarkerLeaveView(req *mapTypes.AOIMakerLeaveView) { clog.Debugf("[aoiMarkerLeaveView] ObjectType = %s, Marker size = %d, Watcher Size = %d", enum.GetObjectTypeName(req.ObjectType), req.Markers.Size(), req.Watchers.Size()) if req.Watchers.Size() == 0 { return } // 军情线 if req.ObjectType == enum.ObjectType_ArmyLine { return } proto := pb.I64List{ List: req.Markers.List(), } sessions.PushPlayers(req.Watchers.List(), nameRoute.PushMapPusher_ObjectDel, &proto) } // aoiMarkerDespawn aoi marker移出aoi系统 func (p *actor) aoiMarkerDespawn(req *mapTypes.AOIMakerDespawn) { clog.Debugf("[aoiMarkerDespawn] ObjectType = %s, Marker size = %d, Watcher Size = %d", enum.GetObjectTypeName(req.ObjectType), req.Markers.Size(), req.Watchers.Size()) if req.Watchers.Size() == 0 { return } // 军情线 if req.ObjectType == enum.ObjectType_ArmyLine { return } proto := pb.I64List{ List: req.Markers.List(), } sessions.PushPlayers(req.Watchers.List(), nameRoute.PushMapPusher_ObjectDel, &proto) } // aoiMarkerUpdate aoi marker更新回调 func (p *actor) aoiMarkerUpdate(req *mapTypes.AOIMarkerUpdate) { clog.Debugf("[aoiMarkerUpdate] ObjectType = %s, Marker size = %d, Watcher Size = %d", enum.GetObjectTypeName(req.ObjectType), req.Markers.Size(), req.Watchers.Size()) if req.Watchers.Size() == 0 { return } watchers := req.Watchers.List() mapObjects := &pb.MapObjects{} mapObjects.ObjectList, mapObjects.LegionList = p.buildMapObjectAndLegion(req.ObjectType, req.Markers) // 先推送 marker 对应的玩家数据和联盟数据给 AOI 观察者 p.playerAndLeaguePush(watchers, mapObjects.ObjectList) // 再推送 marker 对象 sessions.PushPlayers(watchers, nameRoute.PushMapPusher_ObjectUpdate, mapObjects) } func (p *actor) buildMapObjectAndLegion(objectType enum.ObjectType, objectIDs types.Set[int64]) ([]*pb.MapObject, []*pb.MapLegion) { objectList := []*pb.MapObject{} legionList := []*pb.MapLegion{} switch objectType { case enum.ObjectType_Legion: for objectID := range objectIDs { legionTable, ok := p.LegionTables.Get(objectID) if !ok { continue } legionPB := legionTable.ToProto() for _, member := range legionTable.Members { marchTable, ok := p.MarchTables.Get(member.Key) if !ok { continue } legionPB.MarchList = append(legionPB.MarchList, marchTable.ToProto()) } legionList = append(legionList, legionPB) } case enum.ObjectType_March: { for objectID := range objectIDs { marchTable, ok := p.MarchTables.Get(objectID) if !ok { continue } objectList = append(objectList, marchTable.ToProto()) } } case enum.ObjectType_Build: { for objectID := range objectIDs { buildTable, ok := p.BuildTables.Get(objectID) if !ok { continue } siegeTable := p.SiegeTables.GetValue(objectID) objectList = append(objectList, buildTable.ToProto(siegeTable)) } } case enum.ObjectType_Castle: { for objectID := range objectIDs { castleTable, ok := p.CastleTables.Get(objectID) if !ok { continue } siegeTable := p.SiegeTables.GetValue(objectID) proto := castleTable.ToProto(p.LogicTables, siegeTable) if castleTable.FirstOccupyLeague.LeagueID > 0 { if pbMapLeague, ok := pbMapLeagues.Get(castleTable.FirstOccupyLeague.LeagueID); ok { proto.Castle.FirstLeagueName = pbMapLeague.LeagueName proto.Castle.FirstLeagueAbbName = pbMapLeague.LeagueAbbName proto.Castle.FirstLeagueIcon = 0 // TODO: 联盟图标 } } objectList = append(objectList, proto) } } case enum.ObjectType_Res: { for objectID := range objectIDs { resTable, ok := p.ResTables.Get(objectID) if !ok { continue } objectList = append(objectList, resTable.ToProto()) } } case enum.ObjectType_Monster: { for objectID := range objectIDs { monsterTable, ok := p.MonsterTables.Get(objectID) if !ok { continue } objectList = append(objectList, monsterTable.ToProto()) } } } return objectList, legionList } func (p *actor) playerAndLeaguePush(playerIDs []int64, objectList []*pb.MapObject) { players := types.Map[int64, *pb.MapPlayer]{} leagues := types.Map[int64, *pb.MapLeague]{} // 组装地图玩家对象数据 for _, mapObject := range objectList { if mapObject.PlayerID != 0 && !players.Contains(mapObject.PlayerID) { if watcherTable, ok := p.WatcherTables.Get(mapObject.PlayerID); ok { players.Put(mapObject.PlayerID, watcherTable.ToMapPlayer()) } } if mapObject.LeagueID != 0 && !leagues.Contains(mapObject.LeagueID) { if mapLeague, ok := pbMapLeagues.Get(mapObject.LeagueID); ok { leagues.Put(mapObject.LeagueID, mapLeague) } } } if players.Size() > 0 { proto := pb.MapPlayers{} for _, player := range players { proto.List = append(proto.List, player) } sessions.PushPlayers(playerIDs, nameRoute.PushMapPusher_PlayerUpdate, &proto) clog.Debugf("Player update push: watchers = (%v), proto = (%v)", playerIDs, &proto) } if leagues.Size() > 0 { proto := pb.MapLeagues{} for _, league := range leagues { proto.List = append(proto.List, league) } sessions.PushPlayers(playerIDs, nameRoute.PushMapPusher_LeagueUpdate, &proto) clog.Debugf("League update push: watchers = (%v), proto = (%v)", playerIDs, &proto) } } // aoiUpdateMarchState aoi 更新回调 行军状态 func (p *actor) aoiUpdateMarchState(req *mapTypes.AOIMarkerUpdate) { clog.Debugf("[aoiUpdateMarchState] ObjectID = %v, ObjectType = %s, Watcher Size = %d", req.Markers, enum.GetObjectTypeName(req.ObjectType), req.Watchers.Size()) if req.Watchers.Size() == 0 { return } ws := req.Watchers.List() for objectID := range req.Markers { marchTable, ok := p.MarchTables.Get(objectID) if !ok { clog.Warnf("[aoiUpdateMarchState] march not found. objectID = %d", objectID) continue } sessions.PushPlayers(ws, nameRoute.PushMapPusher_MarchState, marchTable.ToStatusProto()) // 通知ui更新 p.PushMapUIMarchState(marchTable.PlayerID, marchTable.ToStatusProto()) } } // aoiUpdateBattle aoi 更新回调 战斗 func (p *actor) aoiUpdateBattle(req *mapTypes.AOIMarkerUpdate) { clog.Debugf("[aoiUpdateBattle] Watcher Size = %d", req.Watchers.Size()) if req.Watchers.Size() == 0 { return } push, ok := getAOIUpdateBattle(req.UpdateID) if !ok { return } sessions.PushPlayers(req.Watchers.List(), nameRoute.PushMapPusher_Battle, push) } func (p *actor) mapPlayerSync(eventData cfacade.IEventData) { clog.Debugf("[mapPlayerSync] event = %+v", eventData) mapWatcherSync, ok := eventData.(*event.MapWatcherSync) if !ok { return } data := mapWatcherSync.Data() watcherTable := p.WatcherTables.GetValue(data.PlayerID) if data.IsFacilitySync { watcherTable.SyncFacilityAttrs(data.FacilityAttrs) p.mapPlayerMainCitySync(watcherTable) } else { watcherTable.Update(data) } } // 处理城建给玩家个人主城的最大耐久加成值 func (p *actor) mapPlayerMainCitySync(watcherTable *db.LogicWatcherTable) { if siegeTable, ok := p.SiegeTables.Get(watcherTable.MainCity); ok { oldDurability := siegeTable.FacilityDurability nowDurability := watcherTable.FacilityAttrs.GetI32(enum.AttrCityLife) if oldDurability != nowDurability { siegeTable.UpdateFacilityDurability(nowDurability) clog.Debugf("main city durability update. playerID = %d, oldDurability = %d, nowDurability = %d", watcherTable.PlayerID, oldDurability, nowDurability) // 推送玩家个人主城建筑耐久变化 if buildTable, ok := p.BuildTables.Get(watcherTable.MainCity); ok && !buildTable.IsHide { p.UpdateObjectFull(buildTable.ObjectID, buildTable.Type) } } } } func (p *actor) mapLeagueSync(eventData cfacade.IEventData) { clog.Debugf("[mapLeagueSync] event = %+v", eventData) mapLeagueSync, ok := eventData.(*event.MapLeagueSync) if !ok { return } mapLeague := mapLeagueSync.MapLeague() pbMapLeagues.Put(mapLeague.LeagueID, mapLeague) }