diff --git a/decoder/api_gym.go b/decoder/api_gym.go index f704b580..01a10216 100644 --- a/decoder/api_gym.go +++ b/decoder/api_gym.go @@ -49,6 +49,7 @@ type ApiGymResult struct { RaidPokemonCostume *int64 `json:"raid_pokemon_costume" doc:"Costume ID of the raid boss"` RaidPokemonEvolution *int64 `json:"raid_pokemon_evolution" doc:"Evolution ID of the raid boss (e.g. mega)"` ArScanEligible *int64 `json:"ar_scan_eligible" doc:"Whether the gym is eligible for AR scanning"` + IsMegaEnhancedEligible *int64 `json:"is_mega_enhanced_eligible"` PowerUpLevel *int64 `json:"power_up_level" doc:"Power-up level of the gym"` PowerUpPoints *int64 `json:"power_up_points" doc:"Power-up points accumulated for the gym"` PowerUpEndTimestamp *int64 `json:"power_up_end_timestamp" doc:"Unix timestamp when the power-up ends"` @@ -94,6 +95,7 @@ func buildGymResult(gym *Gym) ApiGymResult { RaidPokemonCostume: gym.RaidPokemonCostume.Ptr(), RaidPokemonEvolution: gym.RaidPokemonEvolution.Ptr(), ArScanEligible: gym.ArScanEligible.Ptr(), + IsMegaEnhancedEligible: gym.IsMegaEnhancedEligible.Ptr(), PowerUpLevel: gym.PowerUpLevel.Ptr(), PowerUpPoints: gym.PowerUpPoints.Ptr(), PowerUpEndTimestamp: gym.PowerUpEndTimestamp.Ptr(), diff --git a/decoder/api_gym_test.go b/decoder/api_gym_test.go index 9768c1c4..5d9b81a4 100644 --- a/decoder/api_gym_test.go +++ b/decoder/api_gym_test.go @@ -67,7 +67,7 @@ func TestBuildGymResult_GoldenSnapshot(t *testing.T) { t.Fatalf("marshal: %v", err) } - const want = `{"id":"gym-abc","lat":12.3456,"lon":-65.4321,"name":"Test Gym","url":"https://example.com/gym.png","last_modified_timestamp":1699990000,"raid_end_timestamp":1700003600,"raid_spawn_timestamp":null,"raid_battle_timestamp":1700000000,"updated":1699999999,"raid_pokemon_id":150,"guarding_pokemon_id":143,"guarding_pokemon_display":null,"available_slots":3,"team_id":2,"raid_level":5,"enabled":1,"ex_raid_eligible":0,"in_battle":0,"raid_pokemon_move_1":216,"raid_pokemon_move_2":94,"raid_pokemon_form":0,"raid_pokemon_alignment":0,"raid_pokemon_cp":3500,"raid_is_exclusive":0,"cell_id":1234567890123,"deleted":false,"total_cp":12000,"first_seen_timestamp":1699990000,"raid_pokemon_gender":1,"sponsor_id":null,"partner_id":"partner-1","raid_pokemon_costume":0,"raid_pokemon_evolution":0,"ar_scan_eligible":1,"power_up_level":2,"power_up_points":50,"power_up_end_timestamp":null,"description":"A test gym","defenders":null,"rsvps":"[]"}` + const want = `{"id":"gym-abc","lat":12.3456,"lon":-65.4321,"name":"Test Gym","url":"https://example.com/gym.png","last_modified_timestamp":1699990000,"raid_end_timestamp":1700003600,"raid_spawn_timestamp":null,"raid_battle_timestamp":1700000000,"updated":1699999999,"raid_pokemon_id":150,"guarding_pokemon_id":143,"guarding_pokemon_display":null,"available_slots":3,"team_id":2,"raid_level":5,"enabled":1,"ex_raid_eligible":0,"in_battle":0,"raid_pokemon_move_1":216,"raid_pokemon_move_2":94,"raid_pokemon_form":0,"raid_pokemon_alignment":0,"raid_pokemon_cp":3500,"raid_is_exclusive":0,"cell_id":1234567890123,"deleted":false,"total_cp":12000,"first_seen_timestamp":1699990000,"raid_pokemon_gender":1,"sponsor_id":null,"partner_id":"partner-1","raid_pokemon_costume":0,"raid_pokemon_evolution":0,"ar_scan_eligible":1,"is_mega_enhanced_eligible":null,"power_up_level":2,"power_up_points":50,"power_up_end_timestamp":null,"description":"A test gym","defenders":null,"rsvps":"[]"}` if string(got) != want { t.Errorf("wire format changed.\n got: %s\nwant: %s", got, want) diff --git a/decoder/gym.go b/decoder/gym.go index b723b68a..ebc739df 100644 --- a/decoder/gym.go +++ b/decoder/gym.go @@ -45,8 +45,9 @@ type GymData struct { PartnerId null.String `db:"partner_id"` RaidPokemonCostume null.Int `db:"raid_pokemon_costume"` RaidPokemonEvolution null.Int `db:"raid_pokemon_evolution"` - ArScanEligible null.Int `db:"ar_scan_eligible"` - PowerUpLevel null.Int `db:"power_up_level"` + ArScanEligible null.Int `db:"ar_scan_eligible"` + IsMegaEnhancedEligible null.Int `db:"is_mega_enhanced_eligible"` + PowerUpLevel null.Int `db:"power_up_level"` PowerUpPoints null.Int `db:"power_up_points"` PowerUpEndTimestamp null.Int `db:"power_up_end_timestamp"` Description null.String `db:"description"` @@ -479,6 +480,16 @@ func (gym *Gym) SetArScanEligible(v null.Int) { } } +func (gym *Gym) SetIsMegaEnhancedEligible(v null.Int) { + if gym.IsMegaEnhancedEligible != v { + if dbDebugEnabled { + gym.changedFields = append(gym.changedFields, fmt.Sprintf("IsMegaEnhancedEligible:%s->%s", FormatNull(gym.IsMegaEnhancedEligible), FormatNull(v))) + } + gym.IsMegaEnhancedEligible = v + gym.dirty = true + } +} + func (gym *Gym) SetPowerUpLevel(v null.Int) { if gym.PowerUpLevel != v { if dbDebugEnabled { diff --git a/decoder/gym_decode.go b/decoder/gym_decode.go index d12de45a..38cd54ab 100644 --- a/decoder/gym_decode.go +++ b/decoder/gym_decode.go @@ -92,6 +92,7 @@ func (gym *Gym) updateGymFromFort(fortData *pogo.PokemonFortProto, cellId uint64 } gym.SetInBattle(null.IntFrom(util.BoolToInt[int64](fortData.IsInBattle))) gym.SetArScanEligible(null.IntFrom(util.BoolToInt[int64](fortData.IsArScanEligible))) + gym.SetIsMegaEnhancedEligible(null.IntFrom(util.BoolToInt[int64](fortData.IsMegaEnhancedEligible))) gym.SetPowerUpPoints(null.IntFrom(int64(fortData.PowerUpProgressPoints))) powerUpLevel, powerUpEndTimestamp := calculatePowerUpPoints(fortData) diff --git a/decoder/gym_state.go b/decoder/gym_state.go index 5ae4b2e8..7454ac1a 100644 --- a/decoder/gym_state.go +++ b/decoder/gym_state.go @@ -144,55 +144,57 @@ func getOrCreateGymRecord(ctx context.Context, db db.DbDetails, fortId string, c } type GymDetailsWebhook struct { - Id string `json:"id"` - Name string `json:"name"` - Url string `json:"url"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - Team int64 `json:"team"` - GuardPokemonId int64 `json:"guard_pokemon_id"` - SlotsAvailable int64 `json:"slots_available"` - ExRaidEligible int64 `json:"ex_raid_eligible"` - InBattle bool `json:"in_battle"` - SponsorId int64 `json:"sponsor_id"` - PartnerId int64 `json:"partner_id"` - PowerUpPoints int64 `json:"power_up_points"` - PowerUpLevel int64 `json:"power_up_level"` - PowerUpEndTimestamp int64 `json:"power_up_end_timestamp"` - ArScanEligible int64 `json:"ar_scan_eligible"` - Defenders any `json:"defenders"` + Id string `json:"id"` + Name string `json:"name"` + Url string `json:"url"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Team int64 `json:"team"` + GuardPokemonId int64 `json:"guard_pokemon_id"` + SlotsAvailable int64 `json:"slots_available"` + ExRaidEligible int64 `json:"ex_raid_eligible"` + InBattle bool `json:"in_battle"` + SponsorId int64 `json:"sponsor_id"` + PartnerId int64 `json:"partner_id"` + PowerUpPoints int64 `json:"power_up_points"` + PowerUpLevel int64 `json:"power_up_level"` + PowerUpEndTimestamp int64 `json:"power_up_end_timestamp"` + ArScanEligible int64 `json:"ar_scan_eligible"` + IsMegaEnhancedEligible int64 `json:"is_mega_enhanced_eligible"` + Defenders any `json:"defenders"` } type RaidWebhook struct { - GymId string `json:"gym_id"` - GymName string `json:"gym_name"` - GymUrl string `json:"gym_url"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - TeamId int64 `json:"team_id"` - Spawn int64 `json:"spawn"` - Start int64 `json:"start"` - End int64 `json:"end"` - Level int64 `json:"level"` - PokemonId int64 `json:"pokemon_id"` - Cp int64 `json:"cp"` - Gender int64 `json:"gender"` - Form int64 `json:"form"` - Alignment int64 `json:"alignment"` - Costume int64 `json:"costume"` - Evolution int64 `json:"evolution"` - Move1 int64 `json:"move_1"` - Move2 int64 `json:"move_2"` - ExRaidEligible int64 `json:"ex_raid_eligible"` - IsExclusive int64 `json:"is_exclusive"` - SponsorId int64 `json:"sponsor_id"` - PartnerId string `json:"partner_id"` - PowerUpPoints int64 `json:"power_up_points"` - PowerUpLevel int64 `json:"power_up_level"` - PowerUpEndTimestamp int64 `json:"power_up_end_timestamp"` - ArScanEligible int64 `json:"ar_scan_eligible"` - Rsvps json.RawMessage `json:"rsvps"` - RaidSeed null.String `json:"raid_seed"` + GymId string `json:"gym_id"` + GymName string `json:"gym_name"` + GymUrl string `json:"gym_url"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + TeamId int64 `json:"team_id"` + Spawn int64 `json:"spawn"` + Start int64 `json:"start"` + End int64 `json:"end"` + Level int64 `json:"level"` + PokemonId int64 `json:"pokemon_id"` + Cp int64 `json:"cp"` + Gender int64 `json:"gender"` + Form int64 `json:"form"` + Alignment int64 `json:"alignment"` + Costume int64 `json:"costume"` + Evolution int64 `json:"evolution"` + Move1 int64 `json:"move_1"` + Move2 int64 `json:"move_2"` + ExRaidEligible int64 `json:"ex_raid_eligible"` + IsExclusive int64 `json:"is_exclusive"` + SponsorId int64 `json:"sponsor_id"` + PartnerId string `json:"partner_id"` + PowerUpPoints int64 `json:"power_up_points"` + PowerUpLevel int64 `json:"power_up_level"` + PowerUpEndTimestamp int64 `json:"power_up_end_timestamp"` + ArScanEligible int64 `json:"ar_scan_eligible"` + IsMegaEnhancedEligible int64 `json:"is_mega_enhanced_eligible"` + Rsvps json.RawMessage `json:"rsvps"` + RaidSeed null.String `json:"raid_seed"` } func createGymFortWebhooks(gym *Gym) { @@ -231,8 +233,9 @@ func createGymWebhooks(gym *Gym, areas []geo.AreaName) { return 6 } }(), - ExRaidEligible: gym.ExRaidEligible.ValueOrZero(), - InBattle: func() bool { return gym.InBattle.ValueOrZero() != 0 }(), + ExRaidEligible: gym.ExRaidEligible.ValueOrZero(), + IsMegaEnhancedEligible: gym.IsMegaEnhancedEligible.ValueOrZero(), + InBattle: func() bool { return gym.InBattle.ValueOrZero() != 0 }(), Defenders: func() any { if gym.Defenders.Valid { return json.RawMessage(gym.Defenders.ValueOrZero()) @@ -266,34 +269,35 @@ func createGymWebhooks(gym *Gym, areas []geo.AreaName) { } raidHook := RaidWebhook{ - GymId: gym.Id, - GymName: gymName, - GymUrl: gym.Url.ValueOrZero(), - Latitude: gym.Lat, - Longitude: gym.Lon, - TeamId: gym.TeamId.ValueOrZero(), - Spawn: gym.RaidSpawnTimestamp.ValueOrZero(), - Start: gym.RaidBattleTimestamp.ValueOrZero(), - End: gym.RaidEndTimestamp.ValueOrZero(), - Level: gym.RaidLevel.ValueOrZero(), - PokemonId: gym.RaidPokemonId.ValueOrZero(), - Cp: gym.RaidPokemonCp.ValueOrZero(), - Gender: gym.RaidPokemonGender.ValueOrZero(), - Form: gym.RaidPokemonForm.ValueOrZero(), - Alignment: gym.RaidPokemonAlignment.ValueOrZero(), - Costume: gym.RaidPokemonCostume.ValueOrZero(), - Evolution: gym.RaidPokemonEvolution.ValueOrZero(), - Move1: gym.RaidPokemonMove1.ValueOrZero(), - Move2: gym.RaidPokemonMove2.ValueOrZero(), - ExRaidEligible: gym.ExRaidEligible.ValueOrZero(), - IsExclusive: gym.RaidIsExclusive.ValueOrZero(), - SponsorId: gym.SponsorId.ValueOrZero(), - PartnerId: gym.PartnerId.ValueOrZero(), - PowerUpPoints: gym.PowerUpPoints.ValueOrZero(), - PowerUpLevel: gym.PowerUpLevel.ValueOrZero(), - PowerUpEndTimestamp: gym.PowerUpEndTimestamp.ValueOrZero(), - ArScanEligible: gym.ArScanEligible.ValueOrZero(), - Rsvps: rsvps, + GymId: gym.Id, + GymName: gymName, + GymUrl: gym.Url.ValueOrZero(), + Latitude: gym.Lat, + Longitude: gym.Lon, + TeamId: gym.TeamId.ValueOrZero(), + Spawn: gym.RaidSpawnTimestamp.ValueOrZero(), + Start: gym.RaidBattleTimestamp.ValueOrZero(), + End: gym.RaidEndTimestamp.ValueOrZero(), + Level: gym.RaidLevel.ValueOrZero(), + PokemonId: gym.RaidPokemonId.ValueOrZero(), + Cp: gym.RaidPokemonCp.ValueOrZero(), + Gender: gym.RaidPokemonGender.ValueOrZero(), + Form: gym.RaidPokemonForm.ValueOrZero(), + Alignment: gym.RaidPokemonAlignment.ValueOrZero(), + Costume: gym.RaidPokemonCostume.ValueOrZero(), + Evolution: gym.RaidPokemonEvolution.ValueOrZero(), + Move1: gym.RaidPokemonMove1.ValueOrZero(), + Move2: gym.RaidPokemonMove2.ValueOrZero(), + ExRaidEligible: gym.ExRaidEligible.ValueOrZero(), + IsExclusive: gym.RaidIsExclusive.ValueOrZero(), + SponsorId: gym.SponsorId.ValueOrZero(), + PartnerId: gym.PartnerId.ValueOrZero(), + PowerUpPoints: gym.PowerUpPoints.ValueOrZero(), + PowerUpLevel: gym.PowerUpLevel.ValueOrZero(), + PowerUpEndTimestamp: gym.PowerUpEndTimestamp.ValueOrZero(), + ArScanEligible: gym.ArScanEligible.ValueOrZero(), + IsMegaEnhancedEligible: gym.IsMegaEnhancedEligible.ValueOrZero(), + Rsvps: rsvps, RaidSeed: func() null.String { if gym.RaidSeed.Valid { return null.StringFrom(strconv.FormatInt(gym.RaidSeed.Int64, 10)) @@ -369,8 +373,8 @@ func gymWriteDB(db db.DbDetails, gym *Gym, isNewRecord bool) error { ctx := context.Background() if isNewRecord { - res, err := db.GeneralDb.NamedExecContext(ctx, "INSERT INTO gym (id,lat,lon,name,url,last_modified_timestamp,raid_end_timestamp,raid_spawn_timestamp,raid_battle_timestamp,updated,raid_pokemon_id,guarding_pokemon_id,guarding_pokemon_display,available_slots,team_id,raid_level,enabled,ex_raid_eligible,in_battle,raid_pokemon_move_1,raid_pokemon_move_2,raid_pokemon_form,raid_pokemon_alignment,raid_pokemon_cp,raid_is_exclusive,cell_id,deleted,total_cp,first_seen_timestamp,raid_pokemon_gender,sponsor_id,partner_id,raid_pokemon_costume,raid_pokemon_evolution,ar_scan_eligible,power_up_level,power_up_points,power_up_end_timestamp,description, defenders, rsvps) "+ - "VALUES (:id,:lat,:lon,:name,:url,UNIX_TIMESTAMP(),:raid_end_timestamp,:raid_spawn_timestamp,:raid_battle_timestamp,:updated,:raid_pokemon_id,:guarding_pokemon_id,:guarding_pokemon_display,:available_slots,:team_id,:raid_level,:enabled,:ex_raid_eligible,:in_battle,:raid_pokemon_move_1,:raid_pokemon_move_2,:raid_pokemon_form,:raid_pokemon_alignment,:raid_pokemon_cp,:raid_is_exclusive,:cell_id,0,:total_cp,UNIX_TIMESTAMP(),:raid_pokemon_gender,:sponsor_id,:partner_id,:raid_pokemon_costume,:raid_pokemon_evolution,:ar_scan_eligible,:power_up_level,:power_up_points,:power_up_end_timestamp,:description, :defenders, :rsvps)", gym) + res, err := db.GeneralDb.NamedExecContext(ctx, "INSERT INTO gym (id,lat,lon,name,url,last_modified_timestamp,raid_end_timestamp,raid_spawn_timestamp,raid_battle_timestamp,updated,raid_pokemon_id,guarding_pokemon_id,guarding_pokemon_display,available_slots,team_id,raid_level,enabled,ex_raid_eligible,in_battle,raid_pokemon_move_1,raid_pokemon_move_2,raid_pokemon_form,raid_pokemon_alignment,raid_pokemon_cp,raid_is_exclusive,cell_id,deleted,total_cp,first_seen_timestamp,raid_pokemon_gender,sponsor_id,partner_id,raid_pokemon_costume,raid_pokemon_evolution,ar_scan_eligible,is_mega_enhanced_eligible,power_up_level,power_up_points,power_up_end_timestamp,description, defenders, rsvps) "+ + "VALUES (:id,:lat,:lon,:name,:url,UNIX_TIMESTAMP(),:raid_end_timestamp,:raid_spawn_timestamp,:raid_battle_timestamp,:updated,:raid_pokemon_id,:guarding_pokemon_id,:guarding_pokemon_display,:available_slots,:team_id,:raid_level,:enabled,:ex_raid_eligible,:in_battle,:raid_pokemon_move_1,:raid_pokemon_move_2,:raid_pokemon_form,:raid_pokemon_alignment,:raid_pokemon_cp,:raid_is_exclusive,:cell_id,0,:total_cp,UNIX_TIMESTAMP(),:raid_pokemon_gender,:sponsor_id,:partner_id,:raid_pokemon_costume,:raid_pokemon_evolution,:ar_scan_eligible,:is_mega_enhanced_eligible,:power_up_level,:power_up_points,:power_up_end_timestamp,:description, :defenders, :rsvps)", gym) statsCollector.IncDbQuery("insert gym", err) if err != nil { @@ -413,6 +417,7 @@ func gymWriteDB(db db.DbDetails, gym *Gym, isNewRecord bool) error { "raid_pokemon_costume = :raid_pokemon_costume, "+ "raid_pokemon_evolution = :raid_pokemon_evolution, "+ "ar_scan_eligible = :ar_scan_eligible, "+ + "is_mega_enhanced_eligible = :is_mega_enhanced_eligible, "+ "power_up_level = :power_up_level, "+ "power_up_points = :power_up_points, "+ "power_up_end_timestamp = :power_up_end_timestamp,"+ diff --git a/sql/55_gym_mega_enhanced_eligible.down.sql b/sql/55_gym_mega_enhanced_eligible.down.sql new file mode 100644 index 00000000..477b6afc --- /dev/null +++ b/sql/55_gym_mega_enhanced_eligible.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE gym + DROP COLUMN `is_mega_enhanced_eligible`; diff --git a/sql/55_gym_mega_enhanced_eligible.up.sql b/sql/55_gym_mega_enhanced_eligible.up.sql new file mode 100644 index 00000000..d886f687 --- /dev/null +++ b/sql/55_gym_mega_enhanced_eligible.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE gym + ADD `is_mega_enhanced_eligible` tinyint unsigned NOT NULL DEFAULT 0;