parse.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package gen7
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "strings"
  7. "unicode/utf16"
  8. p "github.com/ajswis/go-pkparse-server/pokemon"
  9. )
  10. // Parse accepts a raw pokemon (byte slice) and either returns a Pokemon struct
  11. // with all applicable fields populated or an error depicting the reason for
  12. // failure.
  13. func Parse(rawPokemon p.RawPokemon) (*p.Pokemon, error) {
  14. if err := validateRawPokemon(rawPokemon); err != nil {
  15. return nil, err
  16. }
  17. var pkmn p.Pokemon
  18. pkmn.RawPokemon = &rawPokemon
  19. pkmn.EncryptionConstant = binary.LittleEndian.Uint32(rawPokemon[0x00:0x08])
  20. pkmn.PokedexNumber = toUint16(rawPokemon[0x08:0x0a])
  21. pkmn.HeldItemID = toUint16(rawPokemon[0x0a:0x0c])
  22. pkmn.TrainerID = toUint16(rawPokemon[0x0c:0x0e])
  23. pkmn.SecretID = toUint16(rawPokemon[0x0e:0x10])
  24. pkmn.FullTrainerID = binary.LittleEndian.Uint32(rawPokemon[0x0c:0x10])
  25. pkmn.Experience = binary.LittleEndian.Uint32(rawPokemon[0x10:0x15])
  26. pkmn.AbilityID = rawPokemon[0x14]
  27. pkmn.AbilityNum = rawPokemon[0x14]
  28. pkmn.PID = binary.LittleEndian.Uint32(rawPokemon[0x18:0x1c])
  29. pkmn.NatureID = rawPokemon[0x1c]
  30. genderByte := rawPokemon[0x1d]
  31. pkmn.FatefulEncounter = (genderByte & 0x01) == 1
  32. if (genderByte & 0x02) == 0x02 {
  33. pkmn.Gender = "F"
  34. } else if (genderByte & 0x04) == 0x04 {
  35. pkmn.Gender = ""
  36. } else {
  37. pkmn.Gender = "M"
  38. }
  39. pkmn.FormID = genderByte >> 3
  40. pkmn.HPEV = rawPokemon[0x1e]
  41. pkmn.AtkEV = rawPokemon[0x1f]
  42. pkmn.DefEV = rawPokemon[0x20]
  43. pkmn.SpeEV = rawPokemon[0x21]
  44. pkmn.SpAtkEV = rawPokemon[0x22]
  45. pkmn.SpDefEV = rawPokemon[0x23]
  46. pokerusByte := rawPokemon[0x2b]
  47. pkmn.PokerusDuration = pokerusByte & 15
  48. pkmn.PokerusStrain = pokerusByte >> 4
  49. pkmn.RawNickname = rawPokemon[0x40:0x58]
  50. pkmn.Nickname = binaryToUTF16leString(pkmn.RawNickname)
  51. pkmn.Move1ID = toUint16(rawPokemon[0x5a:0x5c])
  52. pkmn.Move2ID = toUint16(rawPokemon[0x5c:0x5e])
  53. pkmn.Move3ID = toUint16(rawPokemon[0x5e:0x60])
  54. pkmn.Move4ID = toUint16(rawPokemon[0x60:0x62])
  55. pkmn.Move1PP = rawPokemon[0x62]
  56. pkmn.Move2PP = rawPokemon[0x63]
  57. pkmn.Move3PP = rawPokemon[0x64]
  58. pkmn.Move4PP = rawPokemon[0x65]
  59. pkmn.Move1PPUsed = rawPokemon[0x66]
  60. pkmn.Move2PPUsed = rawPokemon[0x67]
  61. pkmn.Move3PPUsed = rawPokemon[0x68]
  62. pkmn.Move4PPUsed = rawPokemon[0x69]
  63. pkmn.EggMove1ID = toUint16(rawPokemon[0x6a:0x6c])
  64. pkmn.EggMove2ID = toUint16(rawPokemon[0x6c:0x6e])
  65. pkmn.EggMove3ID = toUint16(rawPokemon[0x6e:0x70])
  66. pkmn.EggMove4ID = toUint16(rawPokemon[0x70:0x72])
  67. ivBytes := binary.LittleEndian.Uint32(rawPokemon[0x74:0x78])
  68. pkmn.HPIV = ivBytes & 0x1f
  69. pkmn.AtkIV = ivBytes >> 5 & 0x1f
  70. pkmn.DefIV = ivBytes >> 10 & 0x1f
  71. pkmn.SpeIV = ivBytes >> 15 & 0x1f
  72. pkmn.SpAtkIV = ivBytes >> 20 & 0x1f
  73. pkmn.SpDefIV = ivBytes >> 25 & 0x1f
  74. pkmn.IsEgg = ((ivBytes >> 30) % 2) == 1
  75. pkmn.IsNicknamed = ((ivBytes >> 31) % 2) == 1
  76. return &pkmn, nil
  77. }
  78. func binaryToUTF16leString(b []byte) string {
  79. r := bytes.NewReader(b)
  80. u16 := make([]uint16, len(b)/2)
  81. binary.Read(r, binary.LittleEndian, &u16)
  82. runes := utf16.Decode(u16)
  83. s := strings.Split(string(runes), "\u0000")[0]
  84. return s
  85. }
  86. func calculateChecksum(b []byte) uint16 {
  87. var sum uint16
  88. for i := 8; i < 232; i += 2 {
  89. sum += toUint16(b[i : i+2])
  90. }
  91. return sum & 0xffff
  92. }
  93. func toUint16(b []byte) uint16 {
  94. return binary.LittleEndian.Uint16(b)
  95. }
  96. func validateRawPokemon(rawPokemon p.RawPokemon) error {
  97. if l := len(rawPokemon); l != 232 && l != 260 {
  98. return fmt.Errorf("Invalid length for generation 7 pokemon: %d bytes", l)
  99. }
  100. checksumValue := toUint16(rawPokemon[0x06:0x08])
  101. if calculatedChecksum := calculateChecksum(rawPokemon); calculatedChecksum != checksumValue {
  102. return fmt.Errorf("Invalid checksum for generation 7 pokemon")
  103. }
  104. if toUint16(rawPokemon[0x04:0x06]) == 1 || rawPokemon[0x58] == 1 || rawPokemon[0x90] == 1 || rawPokemon[0xc8] == 1 {
  105. return fmt.Errorf("Invalid bytes supplied for generation 7 pokemon")
  106. }
  107. return nil
  108. }