From 936fbeaa6f070313f56fcbda5212e66074b051b3 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 24 Oct 2025 16:43:55 -0700 Subject: [PATCH 1/2] Fix defender parsing gated by gym flag --- main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index adfdd97a..a60eb086 100644 --- a/main.go +++ b/main.go @@ -396,7 +396,9 @@ func decode(ctx context.Context, method int, protoData *ProtoData) { result = decodeGMO(ctx, protoData, getScanParameters(protoData)) processed = true case pogo.Method_METHOD_GYM_GET_INFO: - result = decodeGetGymInfo(ctx, protoData.Data) + if getScanParameters(protoData).ProcessGyms { + result = decodeGetGymInfo(ctx, protoData.Data) + } processed = true case pogo.Method_METHOD_ENCOUNTER: if getScanParameters(protoData).ProcessPokemon { From 8f740db9c7ab52869224c6c47419ca4599e61a62 Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 28 Oct 2025 19:42:51 -0700 Subject: [PATCH 2/2] Add gym parsing to GymInfoOut --- decoder/gym.go | 19 +++++-- decoder/gym_test.go | 117 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 decoder/gym_test.go diff --git a/decoder/gym.go b/decoder/gym.go index b3963c77..168b3fe8 100644 --- a/decoder/gym.go +++ b/decoder/gym.go @@ -305,9 +305,20 @@ func (gym *Gym) updateGymFromFortProto(fortData *pogo.FortDetailsOutProto) *Gym } func (gym *Gym) updateGymFromGymInfoOutProto(gymData *pogo.GymGetInfoOutProto) *Gym { - gym.Id = gymData.GymStatusAndDefenders.PokemonFortProto.FortId - gym.Lat = gymData.GymStatusAndDefenders.PokemonFortProto.Latitude - gym.Lon = gymData.GymStatusAndDefenders.PokemonFortProto.Longitude + status := gymData.GetGymStatusAndDefenders() + gym.Id = status.PokemonFortProto.FortId + gym.Lat = status.PokemonFortProto.Latitude + gym.Lon = status.PokemonFortProto.Longitude + previousCell := gym.CellId + var cellId uint64 + if previousCell.Valid { + cellId = uint64(previousCell.Int64) + } + gym.updateGymFromFort(status.PokemonFortProto, cellId) + if !previousCell.Valid { + // Preserve the unknown state if we did not previously know the cell. + gym.CellId = null.NewInt(0, false) + } // This will have gym defenders in it... if len(gymData.Url) > 0 { @@ -344,7 +355,7 @@ func (gym *Gym) updateGymFromGymInfoOutProto(gymData *pogo.GymGetInfoOutProto) * var defenders []pokemonGymDefender now := time.Now() - for _, protoDefender := range gymData.GymStatusAndDefenders.GymDefender { + for _, protoDefender := range status.GymDefender { motivatedPokemon := protoDefender.MotivatedPokemon pokemonDisplay := motivatedPokemon.Pokemon.PokemonDisplay deploymentTotals := protoDefender.DeploymentTotals diff --git a/decoder/gym_test.go b/decoder/gym_test.go new file mode 100644 index 00000000..feab3b9f --- /dev/null +++ b/decoder/gym_test.go @@ -0,0 +1,117 @@ +package decoder + +import ( + "encoding/json" + "testing" + + "golbat/pogo" +) + +func TestUpdateGymFromGymInfoOutProtoExtractsFortFields(t *testing.T) { + lastModifiedMs := int64(9_876_543_210) + + gym := &Gym{} + gymInfo := &pogo.GymGetInfoOutProto{ + GymStatusAndDefenders: &pogo.GymStatusAndDefendersProto{ + PokemonFortProto: &pogo.PokemonFortProto{ + FortId: "gym-1", + Latitude: 51.5014, + Longitude: -0.1419, + Team: pogo.Team_TEAM_RED, + GuardPokemonId: pogo.HoloPokemonId_BULBASAUR, + GuardPokemonDisplay: &pogo.PokemonDisplayProto{ + Form: pogo.PokemonDisplayProto_Form(1), + }, + GymDisplay: &pogo.GymDisplayProto{ + SlotsAvailable: 2, + TotalGymCp: 1_500, + }, + LastModifiedMs: lastModifiedMs, + Enabled: true, + IsExRaidEligible: true, + IsInBattle: true, + }, + GymDefender: []*pogo.GymDefenderProto{ + { + MotivatedPokemon: &pogo.MotivatedPokemonProto{ + Pokemon: &pogo.PokemonProto{ + PokemonId: pogo.HoloPokemonId_SQUIRTLE, + PokemonDisplay: &pogo.PokemonDisplayProto{}, + }, + CpNow: 1_200, + CpWhenDeployed: 1_300, + MotivationNow: 0.75, + }, + DeploymentTotals: &pogo.DeploymentTotalsProto{ + BattlesLost: 1, + BattlesWon: 5, + TimesFed: 3, + DeploymentDurationMs: 60_000, + }, + }, + }, + }, + Name: "Test Gym", + Url: "https://example.com/gym.jpg", + Description: "Gym description", + } + + gym.updateGymFromGymInfoOutProto(gymInfo) + + if gym.Id != "gym-1" { + t.Fatalf("expected gym id to be gym-1, got %s", gym.Id) + } + + if got := gym.TeamId.ValueOrZero(); got != int64(pogo.Team_TEAM_RED) { + t.Fatalf("expected team id %d, got %d", pogo.Team_TEAM_RED, got) + } + + if got := gym.AvailableSlots.ValueOrZero(); got != 2 { + t.Fatalf("expected available slots 2, got %d", got) + } + + if got := gym.GuardingPokemonId.ValueOrZero(); got != int64(pogo.HoloPokemonId_BULBASAUR) { + t.Fatalf("expected guarding pokemon %d, got %d", pogo.HoloPokemonId_BULBASAUR, got) + } + + if got := gym.InBattle.ValueOrZero(); got != 1 { + t.Fatalf("expected in_battle 1, got %d", got) + } + + if got := gym.LastModifiedTimestamp.ValueOrZero(); got != lastModifiedMs/1000 { + t.Fatalf("expected last_modified_timestamp %d, got %d", lastModifiedMs/1000, got) + } + + if gym.CellId.Valid { + t.Fatalf("expected cell_id to remain invalid when unknown") + } + + if got := gym.Name.ValueOrZero(); got != "Test Gym" { + t.Fatalf("expected name %q, got %q", "Test Gym", got) + } + + if got := gym.Url.ValueOrZero(); got != "https://example.com/gym.jpg" { + t.Fatalf("expected url %q, got %q", "https://example.com/gym.jpg", got) + } + + if got := gym.Description.ValueOrZero(); got != "Gym description" { + t.Fatalf("expected description %q, got %q", "Gym description", got) + } + + if !gym.Defenders.Valid { + t.Fatalf("expected defenders json to be stored") + } + + var storedDefenders []map[string]any + if err := json.Unmarshal([]byte(gym.Defenders.ValueOrZero()), &storedDefenders); err != nil { + t.Fatalf("failed to unmarshal defenders json: %v", err) + } + + if len(storedDefenders) != 1 { + t.Fatalf("expected 1 defender entry, got %d", len(storedDefenders)) + } + + if cpNow, ok := storedDefenders[0]["cp_now"].(float64); !ok || cpNow != 1200 { + t.Fatalf("expected defender cp_now 1200, got %#v", storedDefenders[0]["cp_now"]) + } +}