package gameserver import ( "fmt" "gac-hkrpg-go/internal/common" pb "gac-hkrpg-go/protocol/proto" "sort" ) func cwEquipTrackSync(player *pb.NIHNGPKHEPC) *pb.GridFightSyncUpdateResultScNotify { return cwNotify(&pb.KFNCAIHIHCM{MNLCHEJKDHO: &pb.KFNCAIHIHCM_BMGFDIKDOBE{BMGFDIKDOBE: &pb.MDKHMNKAECP{MIIDIMOCPEB: player.MIIDIMOCPEB}}}) } func cwTraitTrackSync(player *pb.NIHNGPKHEPC) *pb.GridFightSyncUpdateResultScNotify { return cwNotify(&pb.KFNCAIHIHCM{ MNLCHEJKDHO: &pb.KFNCAIHIHCM_HGNDMOODNKF{ HGNDMOODNKF: &pb.FBCIJONDIJE{ ONHDKLIMLNM: append([]uint32(nil), player.ONHDKLIMLNM...), GHJLDDEDJLI: true, }, }, }) } func cwSpotLightTrackSync(spot *pb.GNOBLNOCEHA) *pb.GridFightSyncUpdateResultScNotify { return cwNotify(&pb.KFNCAIHIHCM{ MNLCHEJKDHO: &pb.KFNCAIHIHCM_POLBMPCKFDO{ POLBMPCKFDO: &pb.FFECECBAEEH{ DKEIDONNDCJ: append([]*pb.OGEIHMPCFKA(nil), spot.DKEIDONNDCJ...), }, }, }) } // This Client's CreateServerTrackUpdateInfo takes (roleID, enabled, desired, // equipped, priority, source). AddTrackToLastAndSend passes true; RemoveEquipTrack // passes false with empty lists and source None. The boolean is NOT a delete flag. // Evidence: named RuntimeMethodHandle and bounded PE disassembly in CW notes. func init() { cwHandle("GridFightUpdateEquipTrack", func(s *Session, req *pb.GridFightUpdateEquipTrackCsReq, rsp *pb.GridFightUpdateEquipTrackScRsp) error { rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_PARAM_NOT_MATCH) catalog, data, e := cwPreparingData(s) if e != nil { return nil } player, _, _ := cwComponents(data.DHFOFLFCLAH) if player == nil { return nil } if _, ok := pb.IHMJHLGKLHP_name[int32(req.Source)]; !ok { return nil } equipment, e := common.LoadCurrencyWarsEquipment(catalog) if e != nil { PacketLog("CW_EQUIP_TRACK rejected: " + e.Error()) return nil } entries := append([]*pb.JJOBHGFOGHP(nil), player.MIIDIMOCPEB...) seen := map[uint32]bool{} for _, update := range req.DKEIDONNDCJ { if update == nil || update.BGFFICLCKHE == 0 || seen[update.BGFFICLCKHE] { return nil } seen[update.BGFFICLCKHE] = true if _, ok := pb.IHMJHLGKLHP_name[int32(update.Source)]; !ok { return nil } if _, e = catalog.CapturedRole(update.BGFFICLCKHE); e != nil { PacketLog(fmt.Sprintf("CW_EQUIP_TRACK unknown role=%d", update.BGFFICLCKHE)) return nil } for _, list := range [][]uint32{update.GridFightItemList, update.MCJMHBIECMN} { for _, id := range list { if _, ok := equipment[id]; !ok { return nil } } } kept := make([]*pb.JJOBHGFOGHP, 0, len(entries)+1) for _, old := range entries { // Remove is per-role; upsert replaces just its source. if old.BGFFICLCKHE == update.BGFFICLCKHE && (!update.BJDOINAHDLN || old.Source == update.Source) { continue } kept = append(kept, old) } if update.BJDOINAHDLN { kept = append(kept, &pb.JJOBHGFOGHP{BGFFICLCKHE: update.BGFFICLCKHE, NALMBOOCCIN: update.NALMBOOCCIN, Source: update.Source, MCJMHBIECMN: append([]uint32(nil), update.MCJMHBIECMN...), GridFightItemList: append([]uint32(nil), update.GridFightItemList...)}) } entries = kept } sort.SliceStable(entries, func(i, j int) bool { return entries[i].NALMBOOCCIN < entries[j].NALMBOOCCIN }) player.MIIDIMOCPEB = entries if e = s.saveCurrencyWarsData(data, catalog); e != nil { return nil } if e = cwSend(s, cwEquipTrackSync(player)); e != nil { return e } rsp.Retcode = 0 PacketLog(fmt.Sprintf("CW_EQUIP_TRACK saved updates=%d tracks=%d revision=%d", len(req.DKEIDONNDCJ), len(entries), s.currencyWarsRevision)) return nil }) cwHandle("GridFightUpdateEquipTrackPriority", func(s *Session, req *pb.GridFightUpdateEquipTrackPriorityCsReq, rsp *pb.GridFightUpdateEquipTrackPriorityScRsp) error { rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_PARAM_NOT_MATCH) catalog, data, e := cwPreparingData(s) if e != nil { return nil } player, _, _ := cwComponents(data.DHFOFLFCLAH) if player == nil { return nil } seen := map[uint32]bool{} for _, update := range req.BFCMLCJMLOL { if update == nil || seen[update.BGFFICLCKHE] { return nil } seen[update.BGFFICLCKHE] = true found := false for _, track := range player.MIIDIMOCPEB { if track.BGFFICLCKHE == update.BGFFICLCKHE { track.NALMBOOCCIN = update.NALMBOOCCIN found = true } } if !found { return nil } } sort.SliceStable(player.MIIDIMOCPEB, func(i, j int) bool { return player.MIIDIMOCPEB[i].NALMBOOCCIN < player.MIIDIMOCPEB[j].NALMBOOCCIN }) if e = s.saveCurrencyWarsData(data, catalog); e != nil { return nil } if e = cwSend(s, cwEquipTrackSync(player)); e != nil { return e } rsp.Retcode = 0 return nil }) cwHandleNamed("MCDBJHOCGHI", "IIFPPBCFBBC", func(s *Session, req *pb.MCDBJHOCGHI, rsp *pb.IIFPPBCFBBC) error { rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_PARAM_NOT_MATCH) if req == nil || req.TraitId == 0 { return nil } catalog, data, err := cwPreparingData(s) if err != nil { return nil } player, _, _ := cwComponents(data.DHFOFLFCLAH) if player == nil { return nil } traitsCatalog, err := common.LoadCurrencyWarsTraits(catalog) if err != nil { PacketLog("CW_TRAIT_TRACK rejected: " + err.Error()) return nil } if _, ok := traitsCatalog.Trait(req.TraitId); !ok { PacketLog(fmt.Sprintf("CW_TRAIT_TRACK unknown trait=%d", req.TraitId)) return nil } var updated []uint32 found := false for _, id := range player.ONHDKLIMLNM { if id == req.TraitId { found = true if req.BJDOINAHDLN { updated = append(updated, id) } } else { updated = append(updated, id) } } if req.BJDOINAHDLN && !found { updated = append(updated, req.TraitId) } player.ONHDKLIMLNM = updated if err = s.saveCurrencyWarsData(data, catalog); err != nil { return nil } if err = cwSend(s, cwTraitTrackSync(player)); err != nil { return err } rsp.Retcode = 0 PacketLog(fmt.Sprintf("CW_TRAIT_TRACK trait=%d enabled=%t total=%d revision=%d", req.TraitId, req.BJDOINAHDLN, len(player.ONHDKLIMLNM), s.currencyWarsRevision)) return nil }) cwHandle("GridFightUpdateSpotLightTrack", func(s *Session, req *pb.GridFightUpdateSpotLightTrackCsReq, rsp *pb.GridFightUpdateSpotLightTrackScRsp) error { rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_PARAM_NOT_MATCH) if req == nil { return nil } catalog, data, err := cwPreparingData(s) if err != nil { return nil } cwEnsureSpotlights(data.DHFOFLFCLAH) spotlights := cwSpotlights(data.DHFOFLFCLAH) entries := append([]*pb.OGEIHMPCFKA(nil), spotlights.DKEIDONNDCJ...) for _, update := range req.ACCFJKBOJIJ { if update == nil || update.LDLDLHBCFCF == nil || update.LDLDLHBCFCF.RoleId == 0 { continue } track := update.LDLDLHBCFCF kept := make([]*pb.OGEIHMPCFKA, 0, len(entries)+1) for _, old := range entries { if old.RoleId == track.RoleId { continue } kept = append(kept, old) } if update.BJDOINAHDLN && len(track.DKEIDONNDCJ) > 0 { kept = append(kept, track) } entries = kept } sort.SliceStable(entries, func(i, j int) bool { return entries[i].NALMBOOCCIN < entries[j].NALMBOOCCIN }) spotlights.DKEIDONNDCJ = entries if err = s.saveCurrencyWarsData(data, catalog); err != nil { return nil } if err = cwSend(s, cwSpotLightTrackSync(spotlights)); err != nil { return err } rsp.Retcode = 0 PacketLog(fmt.Sprintf("CW_SPOTLIGHT_TRACK saved updates=%d tracks=%d revision=%d", len(req.ACCFJKBOJIJ), len(entries), s.currencyWarsRevision)) return nil }) }