Переглянути джерело

Add Block C and D file parsing

Andrew Swistak 6 роки тому
батько
коміт
633727306b
2 змінених файлів з 179 додано та 54 видалено
  1. 86 5
      pokemon-parsing/gen7/parse.go
  2. 93 49
      pokemon/pokemon.go

+ 86 - 5
pokemon-parsing/gen7/parse.go

@@ -5,11 +5,14 @@ import (
 	"encoding/binary"
 	"fmt"
 	"strings"
+	"time"
 	"unicode/utf16"
 
 	p "github.com/ajswis/go-pkparse-server/pokemon"
 )
 
+type consoleRegion map[uint8]string
+
 // Parse accepts a raw pokemon (byte slice) and either returns a Pokemon struct
 // with all applicable fields populated or an error depicting the reason for
 // failure.
@@ -17,10 +20,12 @@ func Parse(rawPokemon p.RawPokemon) (*p.Pokemon, error) {
 	if err := validateRawPokemon(rawPokemon); err != nil {
 		return nil, err
 	}
+	consoleRegions := consoleRegion{0x00: "J", 0x01: "U", 0x02: "E", 0x03: "?", 0x04: "C", 0x05: "K", 0x06: "T"}
 
 	var pkmn p.Pokemon
 	pkmn.RawPokemon = &rawPokemon
 
+	// Block A
 	pkmn.EncryptionConstant = binary.LittleEndian.Uint32(rawPokemon[0x00:0x08])
 	pkmn.PokedexNumber = toUint16(rawPokemon[0x08:0x0a])
 	pkmn.HeldItemID = toUint16(rawPokemon[0x0a:0x0c])
@@ -33,16 +38,16 @@ func Parse(rawPokemon p.RawPokemon) (*p.Pokemon, error) {
 	pkmn.PID = binary.LittleEndian.Uint32(rawPokemon[0x18:0x1c])
 	pkmn.NatureID = rawPokemon[0x1c]
 
-	genderByte := rawPokemon[0x1d]
-	pkmn.FatefulEncounter = (genderByte & 0x01) == 1
-	if (genderByte & 0x02) == 0x02 {
+	pkmnGenderByte := rawPokemon[0x1d]
+	pkmn.FatefulEncounter = (pkmnGenderByte & 0x01) == 1
+	if (pkmnGenderByte & 0x02) == 0x02 {
 		pkmn.Gender = "F"
-	} else if (genderByte & 0x04) == 0x04 {
+	} else if (pkmnGenderByte & 0x04) == 0x04 {
 		pkmn.Gender = ""
 	} else {
 		pkmn.Gender = "M"
 	}
-	pkmn.FormID = genderByte >> 3
+	pkmn.FormID = pkmnGenderByte >> 3
 
 	pkmn.HPEV = rawPokemon[0x1e]
 	pkmn.AtkEV = rawPokemon[0x1f]
@@ -55,6 +60,7 @@ func Parse(rawPokemon p.RawPokemon) (*p.Pokemon, error) {
 	pkmn.PokerusDuration = pokerusByte & 15
 	pkmn.PokerusStrain = pokerusByte >> 4
 
+	// Block B
 	pkmn.RawNickname = rawPokemon[0x40:0x58]
 	pkmn.Nickname = binaryToUTF16leString(pkmn.RawNickname)
 
@@ -85,6 +91,68 @@ func Parse(rawPokemon p.RawPokemon) (*p.Pokemon, error) {
 	pkmn.IsEgg = ((ivBytes >> 30) % 2) == 1
 	pkmn.IsNicknamed = ((ivBytes >> 31) % 2) == 1
 
+	// Block C
+	pkmn.RawNotOTName = rawPokemon[0x78:0x90]
+	pkmn.NotOTName = binaryToUTF16leString(pkmn.RawNotOTName)
+	if rawPokemon[0x92] == 1 {
+		pkmn.NotOTGender = "F"
+	} else {
+		pkmn.NotOTGender = "M"
+	}
+
+	pkmn.CurrentHandlerIsOT = rawPokemon[0x93] == 1
+	pkmn.GeoLocation1RegionID = rawPokemon[0x94]
+	pkmn.GeoLocation1CountryID = rawPokemon[0x95]
+	pkmn.GeoLocation2RegionID = rawPokemon[0x96]
+	pkmn.GeoLocation2CountryID = rawPokemon[0x97]
+	pkmn.GeoLocation3RegionID = rawPokemon[0x98]
+	pkmn.GeoLocation3CountryID = rawPokemon[0x99]
+	pkmn.GeoLocation4RegionID = rawPokemon[0x9a]
+	pkmn.GeoLocation4CountryID = rawPokemon[0x9b]
+	pkmn.GeoLocation5RegionID = rawPokemon[0x9c]
+	pkmn.GeoLocation5CountryID = rawPokemon[0x9d]
+
+	pkmn.NotOTFriendship = rawPokemon[0xa2]
+	pkmn.NotOTAffection = rawPokemon[0xa3]
+	pkmn.NotOTMemoryIntensity = rawPokemon[0xa4]
+	pkmn.NotOTMemoryLine = rawPokemon[0xa5]
+	pkmn.NotOTMemoryFeeling = rawPokemon[0xa6]
+	pkmn.NotOTMemoryTextVar = toUint16(rawPokemon[0xa8:0xaa])
+
+	pkmn.Fullness = rawPokemon[0xae]
+	pkmn.Enjoyment = rawPokemon[0xaf]
+
+	// Block D
+	pkmn.RawOTName = rawPokemon[0xb0:0xc8]
+	pkmn.OTName = binaryToUTF16leString(pkmn.RawOTName)
+	pkmn.OTFriendship = rawPokemon[0xca]
+	pkmn.OTAffection = rawPokemon[0xcb]
+	pkmn.OTMemoryIntensity = rawPokemon[0xcc]
+	pkmn.OTMemoryLine = rawPokemon[0xcd]
+	pkmn.OTMemoryTextVar = toUint16(rawPokemon[0xce:0xd0])
+	pkmn.OTMemoryFeeling = rawPokemon[0xd0]
+
+	pkmn.DateEggReceived = uint16ToDatetime(binary.LittleEndian.Uint32(rawPokemon[0xd0:0xd4]))
+	pkmn.DateMet = uint16ToDatetime(binary.LittleEndian.Uint32(rawPokemon[0xd4:0xd8]))
+	pkmn.EggLocationID = toUint16(rawPokemon[0xd8:0xda])
+	pkmn.MetLocationID = toUint16(rawPokemon[0xda:0xdc])
+	pkmn.PokeballID = rawPokemon[0xdc]
+	pkmn.LevelMet = rawPokemon[0xdd] & 0x7f
+
+	if otGenderBit := rawPokemon[0xdd] >> 7; otGenderBit == 1 {
+		pkmn.OTGender = "F"
+	} else {
+		pkmn.OTGender = "M"
+	}
+
+	pkmn.Gen4EncounterTypeID = rawPokemon[0xde]
+	pkmn.OTGameID = rawPokemon[0xdf]
+	pkmn.CountryID = rawPokemon[0xe0]
+	pkmn.RegionID = rawPokemon[0xe1]
+	pkmn.RawConsoleRegion = rawPokemon[0xe2]
+	pkmn.ConsoleRegion = consoleRegions[pkmn.RawConsoleRegion]
+	pkmn.OTLanguageID = rawPokemon[0xe3]
+
 	return &pkmn, nil
 }
 
@@ -126,3 +194,16 @@ func validateRawPokemon(rawPokemon p.RawPokemon) error {
 
 	return nil
 }
+
+func uint16ToDatetime(i uint32) int64 {
+	if i == 0 {
+		return 0
+	}
+
+	year := int((i & 0xff) + 2000)
+	month := time.Month(int((i >> 8) & 0xff))
+	day := int((i >> 16) & 0xff)
+	date := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
+
+	return date.Unix()
+}

+ 93 - 49
pokemon/pokemon.go

@@ -6,53 +6,97 @@ type RawPokemon []byte
 // Pokemon is a struct the has fields for all relevant pokemon data from a
 // RawPokemon.
 type Pokemon struct {
-	RawPokemon         *RawPokemon `json:"raw_pokemon"`
-	EncryptionConstant uint32      `json:"encryption_constant"`
-	PokedexNumber      uint16      `json:"pokedex_number"`
-	HeldItemID         uint16      `json:"held_item_id"`
-	TrainerID          uint16      `json:"trainer_id"`
-	SecretID           uint16      `json:"secret_id"`
-	FullTrainerID      uint32      `json:"full_trainer_id"`
-	Experience         uint32      `json:"experience"`
-	AbilityID          uint8       `json:"ability_id"`
-	AbilityNum         uint8       `json:"Ability_number"`
-	PID                uint32      `json:"pid"`
-	NatureID           uint8       `json:"nature_id"`
-	FatefulEncounter   bool        `json:"fateful_encounter"`
-	Gender             string      `json:"gender"`
-	FormID             uint8       `json:"form_id"`
-	HPEV               uint8       `json:"hp_ev"`
-	AtkEV              uint8       `json:"attack_ev"`
-	DefEV              uint8       `json:"defense_ev"`
-	SpeEV              uint8       `json:"speed_ev"`
-	SpAtkEV            uint8       `json:"special_attack_ev"`
-	SpDefEV            uint8       `json:"special_defense_ev"`
-	PokerusDuration    uint8       `json:"pokerus_duration"`
-	PokerusStrain      uint8       `json:"pokerus_strain"`
-	RawNickname        []byte      `json:"raw_nickname"`
-	Nickname           string      `json:"nickname"`
-	Move1ID            uint16      `json:"move_1_id"`
-	Move2ID            uint16      `json:"move_2_id"`
-	Move3ID            uint16      `json:"move_3_id"`
-	Move4ID            uint16      `json:"move_4_id"`
-	Move1PP            uint8       `json:"move_1_pp"`
-	Move2PP            uint8       `json:"move_2_pp"`
-	Move3PP            uint8       `json:"move_3_pp"`
-	Move4PP            uint8       `json:"move_4_pp"`
-	Move1PPUsed        uint8       `json:"move_1_pp_used"`
-	Move2PPUsed        uint8       `json:"move_2_pp_used"`
-	Move3PPUsed        uint8       `json:"move_3_pp_used"`
-	Move4PPUsed        uint8       `json:"move_4_pp_used"`
-	EggMove1ID         uint16      `json:"egg_move_1_id"`
-	EggMove2ID         uint16      `json:"egg_move_2_id"`
-	EggMove3ID         uint16      `json:"egg_move_3_id"`
-	EggMove4ID         uint16      `json:"egg_move_4_id"`
-	HPIV               uint32      `json:"hp_iv"`
-	AtkIV              uint32      `json:"attack_iv"`
-	DefIV              uint32      `json:"defense_iv"`
-	SpeIV              uint32      `json:"speed_iv"`
-	SpAtkIV            uint32      `json:"special_attack_iv"`
-	SpDefIV            uint32      `json:"special_defense_iv"`
-	IsEgg              bool        `json:"is_egg"`
-	IsNicknamed        bool        `json:"is_nicknamed"`
+	RawPokemon            *RawPokemon `json:"raw_pokemon"`
+	EncryptionConstant    uint32      `json:"encryption_constant"`
+	PokedexNumber         uint16      `json:"pokedex_number"`
+	HeldItemID            uint16      `json:"held_item_id"`
+	TrainerID             uint16      `json:"trainer_id"`
+	SecretID              uint16      `json:"secret_id"`
+	FullTrainerID         uint32      `json:"full_trainer_id"`
+	Experience            uint32      `json:"experience"`
+	AbilityID             uint8       `json:"ability_id"`
+	AbilityNum            uint8       `json:"Ability_number"`
+	PID                   uint32      `json:"pid"`
+	NatureID              uint8       `json:"nature_id"`
+	FatefulEncounter      bool        `json:"fateful_encounter"`
+	Gender                string      `json:"gender"`
+	FormID                uint8       `json:"form_id"`
+	HPEV                  uint8       `json:"hp_ev"`
+	AtkEV                 uint8       `json:"attack_ev"`
+	DefEV                 uint8       `json:"defense_ev"`
+	SpeEV                 uint8       `json:"speed_ev"`
+	SpAtkEV               uint8       `json:"special_attack_ev"`
+	SpDefEV               uint8       `json:"special_defense_ev"`
+	PokerusDuration       uint8       `json:"pokerus_duration"`
+	PokerusStrain         uint8       `json:"pokerus_strain"`
+	RawNickname           []byte      `json:"raw_nickname"`
+	Nickname              string      `json:"nickname"`
+	Move1ID               uint16      `json:"move_1_id"`
+	Move2ID               uint16      `json:"move_2_id"`
+	Move3ID               uint16      `json:"move_3_id"`
+	Move4ID               uint16      `json:"move_4_id"`
+	Move1PP               uint8       `json:"move_1_pp"`
+	Move2PP               uint8       `json:"move_2_pp"`
+	Move3PP               uint8       `json:"move_3_pp"`
+	Move4PP               uint8       `json:"move_4_pp"`
+	Move1PPUsed           uint8       `json:"move_1_pp_used"`
+	Move2PPUsed           uint8       `json:"move_2_pp_used"`
+	Move3PPUsed           uint8       `json:"move_3_pp_used"`
+	Move4PPUsed           uint8       `json:"move_4_pp_used"`
+	EggMove1ID            uint16      `json:"egg_move_1_id"`
+	EggMove2ID            uint16      `json:"egg_move_2_id"`
+	EggMove3ID            uint16      `json:"egg_move_3_id"`
+	EggMove4ID            uint16      `json:"egg_move_4_id"`
+	HPIV                  uint32      `json:"hp_iv"`
+	AtkIV                 uint32      `json:"attack_iv"`
+	DefIV                 uint32      `json:"defense_iv"`
+	SpeIV                 uint32      `json:"speed_iv"`
+	SpAtkIV               uint32      `json:"special_attack_iv"`
+	SpDefIV               uint32      `json:"special_defense_iv"`
+	IsEgg                 bool        `json:"is_egg"`
+	IsNicknamed           bool        `json:"is_nicknamed"`
+	RawNotOTName          []byte      `json:"raw_not_ot_name"`
+	NotOTName             string      `json:"not_ot_name"`
+	NotOTGender           string      `json:"not_ot_gender"`
+	CurrentHandlerIsOT    bool        `json:"current_handler_is_ot"`
+	GeoLocation1RegionID  uint8       `json:"geo_location_1_region_id"`
+	GeoLocation1CountryID uint8       `json:"geo_location_1_country_id"`
+	GeoLocation2RegionID  uint8       `json:"geo_location_2_region_id"`
+	GeoLocation2CountryID uint8       `json:"geo_location_2_country_id"`
+	GeoLocation3RegionID  uint8       `json:"geo_location_3_region_id"`
+	GeoLocation3CountryID uint8       `json:"geo_location_3_country_id"`
+	GeoLocation4RegionID  uint8       `json:"geo_location_4_region_id"`
+	GeoLocation4CountryID uint8       `json:"geo_location_4_country_id"`
+	GeoLocation5RegionID  uint8       `json:"geo_location_5_region_id"`
+	GeoLocation5CountryID uint8       `json:"geo_location_5_country_id"`
+	NotOTFriendship       uint8       `json:"not_ot_friendship"`
+	NotOTAffection        uint8       `json:"not_ot_affection"`
+	NotOTMemoryIntensity  uint8       `json:"not_ot_memory_intensity"`
+	NotOTMemoryLine       uint8       `json:"not_ot_memory_line"`
+	NotOTMemoryFeeling    uint8       `json:"not_ot_memory_feeling"`
+	NotOTMemoryTextVar    uint16      `json:"not_ot_memory_text_var"`
+	Fullness              uint8       `json:"fullness"`
+	Enjoyment             uint8       `json:"enjoyment"`
+	RawOTName             []byte      `json:"raw_ot_name"`
+	OTName                string      `json:"ot_name"`
+	OTFriendship          uint8       `json:"ot_friendship"`
+	OTAffection           uint8       `json:"ot_affection"`
+	OTMemoryIntensity     uint8       `json:"ot_memory_intensity"`
+	OTMemoryLine          uint8       `json:"ot_memory_line"`
+	OTMemoryTextVar       uint16      `json:"ot_memory_text_var"`
+	OTMemoryFeeling       uint8       `json:"ot_memory_feeling"`
+	DateEggReceived       int64       `json:"date_egg_received"`
+	DateMet               int64       `json:"date_met"`
+	EggLocationID         uint16      `json:"egg_location_id"`
+	MetLocationID         uint16      `json:"met_location_id"`
+	PokeballID            uint8       `json:"pokeball_id"`
+	LevelMet              uint8       `json:"level_met"`
+	OTGender              string      `json:"ot_gender"`
+	Gen4EncounterTypeID   uint8       `json:"gen_4_encounter_type_id"`
+	OTGameID              uint8       `json:"OTGameID"`
+	CountryID             uint8       `json:"CountryID"`
+	RegionID              uint8       `json:"RegionID"`
+	RawConsoleRegion      uint8       `json:"raw_console_region"`
+	ConsoleRegion         string      `json:"console_region"`
+	OTLanguageID          uint8       `json:"ot_language_id"`
 }