Mega update

- Support pogo app 0.35.0
- Fixed encountering and catch pokemons
- Save catched pokemon and items inside db
- Added various base tables
- Spawn wild pokemon to players
- Added checkchallenge req/res support
- Fixed various mysql bugs
- Fort details now auto show latest pogoserver version
- Fixed game master parsing bug
- Dump assets for various platforms
This commit is contained in:
Felix
2016-08-23 14:20:01 +02:00
parent 08bca57a90
commit 1cc01c2b3c
27 changed files with 1031 additions and 2769 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "POGOServer",
"version": "0.4.0",
"version": "0.4.2",
"description": "",
"repository": {
"type": "git",
@@ -33,7 +33,7 @@
"directory-tree": "^1.1.0",
"nodegit": "^0.14.1",
"fs-extra": "^0.30.0",
"pokemongo-protobuf": "^1.10.0",
"pokemongo-protobuf": "git+https://github.com/maierfelix/pokemon-go-protobuf-node.git",
"pcrypt": "git+https://github.com/laverdet/pcrypt.git"
},
"devDependencies": {}

View File

@@ -7,9 +7,9 @@ import CFG from "../../cfg";
*/
export function getQueryByColumnFromTable(column, value, table) {
return new Promise((resolve) => {
this.db.instance.query(`SELECT * FROM ${table} WHERE ${column}=? LIMIT 1`, [value], (e, rows) => {
this.db.instance.query(`SELECT * FROM ${table} WHERE ${column}=?`, [value], (e, rows) => {
if (e) console.log(e);
if (rows && rows.length) resolve(rows[0]);
if (rows && rows.length) resolve(rows);
else resolve(void 0);
});
});

View File

@@ -59,6 +59,20 @@ export function createUser(obj) {
}
/**
* @param {Object} obj
*/
export function createOwnedPokemon(obj) {
let query = this.getOwnedPkmnQuery("INSERT INTO", "");
let data = this.getOwnedPkmnQueryData(obj);
return new Promise((resolve) => {
this.db.instance.query(query, data, resolve);
});
}
/**
* @param {Object} obj
*/
@@ -71,4 +85,18 @@ export function updateUser(obj) {
this.db.instance.query(query, data, resolve);
});
}
/**
* @param {Object} obj
*/
export function updateUserItems(obj) {
let query = this.getUserItemQuery("UPDATE", "WHERE email=? LIMIT 1");
let data = this.getUserItemQueryData(obj);
return new Promise((resolve) => {
this.db.instance.query(query, data, resolve);
});
}

View File

@@ -10,6 +10,7 @@ export function getUserQuery(cmd, after) {
username=?,
email=?,
exp=?,
level=?,
stardust=?,
pokecoins=?,
team=?,
@@ -31,61 +32,16 @@ export function getUserQuery(cmd, after) {
`);
}
export function getUserItemQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_USERS_TABLE}
SET
item_poke_ball=?,
item_great_ball=?,
item_ultra_ball=?,
item_master_ball=?,
item_potion=?,
item_super_potion=?,
item_hyper_potion=?,
item_max_potion=?,
item_revive=?,
item_max_revive=?,
item_lucky_egg=?,
item_incense_ordinary=?,
item_incense_spicy=?,
item_incense_cool=?,
item_incense_floral=?,
item_troy_disk=?,
item_razz_berry=?,
item_bluk_berry=?,
item_nanab_berry=?,
item_wepar_berry=?,
item_pinap_berry=?,
item_incubator_basic=?,
item_incubator_basic_unlimited=?,
item_pokemon_storage_upgrade=?,
item_item_storage_upgrade=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getUserItemQueryData(obj) {
console.log(obj);
return ([]);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getUserQueryData(obj) {
return ([
obj.username,
obj.email,
obj.exp,
obj.level,
obj.stardust,
obj.pokecoins,
obj.team,
@@ -106,8 +62,166 @@ export function getUserQueryData(obj) {
obj.eyes,
obj.gender,
obj.backpack,
// where
// WHERE
obj.email
]);
}
/**
* @return {String}
*/
export function getOwnedPkmnQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_OWNED_PKMN_TABLE}
SET
owner_id=?,
pokemon_id=?,
cp=?,
stamina=?,
stamina_max=?,
move_1=?,
move_2=?,
deployed_fort_id=?,
is_egg=?,
egg_km_walked_target=?,
egg_km_walked_start=?,
origin=?,
height_m=?,
weight_kg=?,
individual_attack=?,
individual_defense=?,
individual_stamina=?,
cp_multiplier=?,
pokeball=?,
captured_cell_id=?,
battles_attacked=?,
battles_defended=?,
egg_incubator_id=?,
creation_time_ms=?,
num_upgrades=?,
additional_cp_multiplier=?,
favorite=?,
nickname=?,
from_fort=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getOwnedPkmnQueryData(obj) {
return ([
obj.owner_id,
obj.pokemon_id,
obj.cp,
obj.stamina,
obj.stamina_max,
obj.move_1,
obj.move_2,
obj.deployed_fort_id || "",
obj.is_egg || 0,
obj.egg_km_walked_target || 0,
obj.egg_km_walked_start || 0,
obj.origin || 0,
obj.height_m,
obj.weight_kg,
obj.individual_attack,
obj.individual_defense,
obj.individual_stamina,
obj.cp_multiplier,
obj.pokeball,
obj.captured_cell_id || 0,
obj.battles_attacked || 0,
obj.battles_defended || 0,
obj.egg_incubator_id || "",
obj.creation_time_ms,
obj.num_upgrades || 0,
obj.additional_cp_multiplier || 0,
obj.favorite || 0,
obj.nickname || "",
obj.from_fort || 0
]);
}
export function getUserItemQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_USERS_TABLE}
SET
item_poke_ball=?,
item_great_ball=?,
item_ultra_ball=?,
item_master_ball=?,
item_potion=?,
item_super_potion=?,
item_hyper_potion=?,
item_max_potion=?,
item_revive=?,
item_max_revive=?,
item_lucky_egg=?,
item_incense_ordinary=?,
item_incense_spicy=?,
item_incense_cool=?,
item_incense_floral=?,
item_troy_disk=?,
item_razz_berry=?,
item_bluk_berry=?,
item_nanab_berry=?,
item_wepar_berry=?,
item_pinap_berry=?,
item_incubator_basic=?,
item_incubator_basic_unlimited=?,
item_pokemon_storage_upgrade=?,
item_storage_upgrade=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getUserItemQueryData(obj) {
let items = [];
for (let key in obj.items) {
items.push(obj.items[key]);
};
let email = obj.email;
obj = obj.items;
return ([
obj.poke_ball,
obj.great_ball,
obj.ultra_ball,
obj.master_ball,
obj.potion,
obj.super_potion,
obj.hyper_potion,
obj.max_potion,
obj.revive,
obj.max_revive,
obj.lucky_egg,
obj.incense_ordinary,
obj.incense_spicy,
obj.incense_cool,
obj.incense_floral,
obj.troy_disk,
obj.razz_berry,
obj.bluk_berry,
obj.nanab_berry,
obj.wepar_berry,
obj.pinap_berry,
obj.incubator_basic,
obj.incubator_basic_unlimited,
obj.pokemon_storage_upgrade,
obj.storage_upgrade,
// WHERE
email
]);
}

View File

@@ -0,0 +1,8 @@
id int(15) NOT NULL AUTO_INCREMENT,
fort_id varchar(42) NOT NULL,
latitude double NOT NULL,
longitude double NOT NULL,
enabled tinyint(1) NOT NULL,
items_awarded varchar(42) NOT NULL,
experience_awarded int(10) NOT NULL
PRIMARY KEY (id)

View File

@@ -0,0 +1,8 @@
id int(15) NOT NULL AUTO_INCREMENT,
fort_id varchar(42) NOT NULL,
latitude double NOT NULL,
longitude double NOT NULL,
enabled tinyint(1) NOT NULL,
items_awarded varchar(42) NOT NULL,
experience_awarded int(10) NOT NULL
PRIMARY KEY (id)

View File

@@ -1,47 +1,48 @@
id int(11) NOT NULL AUTO_INCREMENT,
username longtext NOT NULL,
email longtext NOT NULL,
exp int(255) NOT NULL,
stardust int(255) NOT NULL,
pokecoins int(255) NOT NULL,
team int(11) NOT NULL,
latitude double NOT NULL,
longitude double NOT NULL,
altitude int(255) NOT NULL,
send_marketing_emails tinyint(1) NOT NULL,
send_push_notifications tinyint(1) NOT NULL,
skin int(11) NOT NULL,
hair int(11) NOT NULL,
shirt int(11) NOT NULL,
pants int(11) NOT NULL,
hat int(11) NOT NULL,
shoes int(11) NOT NULL,
eyes int(11) NOT NULL,
gender int(11) NOT NULL,
backpack int(11) NOT NULL,
item_poke_ball int(11) NOT NULL,
item_great_ball int(11) NOT NULL,
item_ultra_ball int(11) NOT NULL,
item_master_ball int(11) NOT NULL,
item_potion int(11) NOT NULL,
item_super_potion int(11) NOT NULL,
item_hyper_potion int(11) NOT NULL,
item_max_potion int(11) NOT NULL,
item_revive int(11) NOT NULL,
item_max_revive int(11) NOT NULL,
item_lucky_egg int(11) NOT NULL,
item_incense_ordinary int(11) NOT NULL,
item_incense_spicy int(11) NOT NULL,
item_incense_cool int(11) NOT NULL,
item_incense_floral int(11) NOT NULL,
item_troy_disk int(11) NOT NULL,
item_razz_berry int(11) NOT NULL,
item_bluk_berry int(11) NOT NULL,
item_nanab_berry int(11) NOT NULL,
item_wepar_berry int(11) NOT NULL,
item_pinap_berry int(11) NOT NULL,
item_incubator_basic int(11) NOT NULL,
item_incubator_basic_unlimited int(11) NOT NULL,
item_pokemon_storage_upgrade int(11) NOT NULL,
item_item_storage_upgrade int(11) NOT NULL,
`id` int(11) NOT NULL,
`username` longtext NOT NULL,
`email` longtext NOT NULL,
`exp` int(255) NOT NULL,
`level` int(11) NOT NULL,
`stardust` int(255) NOT NULL,
`pokecoins` int(255) NOT NULL,
`team` int(11) NOT NULL,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`altitude` int(255) NOT NULL,
`send_marketing_emails` tinyint(1) NOT NULL,
`send_push_notifications` tinyint(1) NOT NULL,
`skin` int(11) NOT NULL,
`hair` int(11) NOT NULL,
`shirt` int(11) NOT NULL,
`pants` int(11) NOT NULL,
`hat` int(11) NOT NULL,
`shoes` int(11) NOT NULL,
`eyes` int(11) NOT NULL,
`gender` int(11) NOT NULL,
`backpack` int(11) NOT NULL,
`item_poke_ball` int(11) NOT NULL,
`item_great_ball` int(11) NOT NULL,
`item_ultra_ball` int(11) NOT NULL,
`item_master_ball` int(11) NOT NULL,
`item_potion` int(11) NOT NULL,
`item_super_potion` int(11) NOT NULL,
`item_hyper_potion` int(11) NOT NULL,
`item_max_potion` int(11) NOT NULL,
`item_revive` int(11) NOT NULL,
`item_max_revive` int(11) NOT NULL,
`item_lucky_egg` int(11) NOT NULL,
`item_incense_ordinary` int(11) NOT NULL,
`item_incense_spicy` int(11) NOT NULL,
`item_incense_cool` int(11) NOT NULL,
`item_incense_floral` int(11) NOT NULL,
`item_troy_disk` int(11) NOT NULL,
`item_razz_berry` int(11) NOT NULL,
`item_bluk_berry` int(11) NOT NULL,
`item_nanab_berry` int(11) NOT NULL,
`item_wepar_berry` int(11) NOT NULL,
`item_pinap_berry` int(11) NOT NULL,
`item_incubator_basic` int(11) NOT NULL,
`item_incubator_basic_unlimited` int(11) NOT NULL,
`item_pokemon_storage_upgrade` int(11) NOT NULL,
`item_storage_upgrade` int(11) NOT NULL,
PRIMARY KEY (id)

View File

@@ -59,6 +59,7 @@ class GameServer {
this.passedTicks = 0;
this.clients = [];
this.wild_pokemons = [];
this.greet();

View File

@@ -0,0 +1,28 @@
{
"fort_settings": {
"interaction_range_meters": 40,
"max_total_deployed_pokemon": 10,
"max_player_deployed_pokemon": 1,
"deploy_stamina_multiplier": 8,
"deploy_attack_multiplier": 0,
"far_interaction_range_meters": 1000
},
"map_settings": {
"pokemon_visible_range": 70,
"poke_nav_range_meters": 751,
"encounter_range_meters": 50,
"get_map_objects_min_refresh_seconds": 10,
"get_map_objects_max_refresh_seconds": 30,
"get_map_objects_min_distance_meters": 10
},
"inventory_settings": {
"max_pokemon": 1000,
"max_bag_items": 1000,
"base_pokemon": 250,
"base_bag_items": 350,
"base_eggs": 9
},
"pokemon_settings": {
}
}

View File

@@ -1,6 +1,8 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../../cfg";
/**
* @return {Object}
*/
@@ -8,7 +10,7 @@ export default function AuthTicket() {
let buffer = ({
start: new Buffer(""),
"expire_timestamp_ms": new Date.getTime(),
"expire_timestamp_ms": new Date().getTime() + CFG.PLAYER_CONNECTION_TIMEOUT,
end: new Buffer("")
});

View File

@@ -0,0 +1,52 @@
import CFG from "../../cfg";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Request} req
* @return {Object}
*/
export default function CatchPokemon(encounter, player, req) {
let obj = {
"owner_id": -1,
"encounter_id": encounter.encounter_id,
"spawn_point_id": "87bdcd88cb5",
"captured_cell_id": "9781199952939057152",
pokemon_id: encounter.pokemon_id,
cp: encounter.cp,
"move_1": "BUG_BITE_FAST",
"move_2": "STRUGGLE",
"stamina": 10,
"stamina_max": 10,
height_m: 0.30962005257606506,
weight_kg: 3.3212273120880127,
"pokeball": "ITEM_POKE_BALL",
"creation_time_ms": new Date().getTime(),
"cp_multiplier": 0.16639786958694458,
individual_attack: 7,
individual_defense: 13,
individual_stamina: 3
};
if (!req.hit_pokemon) {
return ({
status: 'CATCH_MISSED'
});
} else {
return ({
pkmn: obj,
buffer: {
status: 'CATCH_SUCCESS',
captured_pokemon_id: encounter.encounter_id,
capture_award: {
activity_type: ['ACTIVITY_CATCH_POKEMON'],
xp: [100],
candy: [3],
stardust: [100]
}
}
});
}
}

View File

@@ -0,0 +1,17 @@
import CFG from "../../cfg";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Request} req
* @return {Object}
*/
export default function CheckChallenge(req) {
let buffer = ({
challenge_url: " "
});
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.CheckChallengeResponse");
}

View File

@@ -24,7 +24,7 @@ export default function DownloadSettings() {
"poke_nav_range_meters": 751.0156862745098,
"encounter_range_meters": 50.25098039215686,
"get_map_objects_min_refresh_seconds": 10.007843017578125,
"get_map_objects_max_refresh_seconds": 30.01568603515625,
"get_map_objects_max_refresh_seconds": 11.01568603515625,
"get_map_objects_min_distance_meters": 10.007843017578125,
"google_maps_api_key": CFG.GMAPS_KEY
},

View File

@@ -9,43 +9,35 @@ import { decodeLong } from "../utils";
* @param {Request} req
* @return {Object}
*/
export default function Encounter(req) {
console.log(req.encounter_id, req.player_latitude, req.player_longitude);
export default function Encounter(encounter, req) {
let buffer = ({
"wild_pokemon": {
"encounter_id": req.encounter_id,
"last_modified_timestamp_ms": new Date().getTime(),
"latitude": req.player_latitude,
"longitude": req.player_longitude,
"spawn_point_id": "87bdcd8ec57",
"pokemon_data": {
"pokemon_id": "MEWTWO",
"cp": 164,
"stamina": 38,
"stamina_max": 38,
"move_1": "TACKLE_FAST",
"move_2": "BODY_SLAM",
"height_m": 0.36679142713546753,
"weight_kg": 9.639217376708984,
"individual_attack": 15,
"individual_defense": 1,
"individual_stamina": 9,
"cp_multiplier": 0.3210875988006592
wild_pokemon: {
encounter_id: encounter.encounter_id,
last_modified_timestamp_ms: '1471852141657',
latitude: encounter.latitude,
longitude: encounter.longitude,
spawn_point_id: '87bdcd8f2e9',
pokemon_data: {
pokemon_id: encounter.pokemon_id,
cp: encounter.cp,
stamina: 10,
stamina_max: 10,
move_1: "BUG_BITE_FAST",
move_2: "STRUGGLE",
height_m: 0.30962005257606506,
weight_kg: 3.3212273120880127,
individual_attack: 7,
individual_defense: 13,
individual_stamina: 3,
cp_multiplier: 0.16639786958694458
},
"time_till_hidden_ms": 857876
time_till_hidden_ms: 860075
},
"status": "ENCOUNTER_SUCCESS",
"capture_probability": {
"pokeball_type": [
"ITEM_POKE_BALL",
"ITEM_GREAT_BALL",
"ITEM_ULTRA_BALL"
],
"capture_probability": {
"0": 0.49830639362335205,
"1": 0.6446487903594971,
"2": 0.7483035326004028
}
status: 'ENCOUNTER_SUCCESS',
capture_probability: {
pokeball_type: ['ITEM_POKE_BALL', 'ITEM_GREAT_BALL', 'ITEM_ULTRA_BALL'],
capture_probability: [1, 1, 1]
}
});

View File

@@ -11,7 +11,7 @@ export default function FortDetails(req) {
let buffer = ({
"fort_id": req.fort_id,
"name": "POGOserver v0.3.5",
"name": `POGOserver v${CFG.VERSION}`,
"image_urls": [
"http://thecatapi.com/api/images/get?format=src&type=png"
],

View File

@@ -4,26 +4,34 @@ import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
* @param {Player} player
* @return {Buffer}
*/
export default function FortSearch(obj) {
export default function FortSearch(player) {
let ii = 0;
let amount = 5;
let items = [];
let name = "ultra_ball";
let amount = 5;
let exp = 50;
while (++ii < amount) {
items.push({
"item_id": "ITEM_MASTER_BALL",
"item_id": "ITEM_" + name.toUpperCase(),
"item_count": 1
})
});
};
player.items[name] += amount;
player.exp += exp;
console.log(player.items[name]);
let buffer = ({
"result": "SUCCESS",
"items_awarded": items,
"experience_awarded": 50,
"experience_awarded": exp,
"cooldown_complete_timestamp_ms": "1471780158665",
"chain_hack_sequence_number": 2,
"$unknownFields": []

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -85,48 +85,15 @@ function buildPlayerData(obj) {
}
/**
* @param {Object} obj
* @return {Object}
*/
export default function GetPlayer(obj) {
let data = buildPlayerData(obj);
let packet = getPlayerDataPacket(data);
let buffer = {
"success": true,
"player_data": {
"creation_timestamp_ms": "1471096437979",
"username": "Administrator",
"team": "YELLOW",
"tutorial_state": [
"LEGAL_SCREEN",
"AVATAR_SELECTION",
"POKEMON_CAPTURE",
"NAME_SELECTION",
"FIRST_TIME_EXPERIENCE_COMPLETE"
],
"avatar": {},
"max_pokemon_storage": 250,
"max_item_storage": 350,
"daily_bonus": {},
"equipped_badge": {},
"contact_settings": {
"send_marketing_emails": true
},
"currencies": [
{
"name": "POKECOIN",
"amount": 1339
},
{
"name": "STARDUST",
"amount": 7681
}
]
},
"$unknownFields": []
success: true,
player_data: packet
};
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerResponse"));

View File

@@ -5,8 +5,9 @@ import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Buffer} master
* @return {Object}
*/
export default function ItemTemplates() {
return (fs.readFileSync("data/game_master"));
export default function ItemTemplates(master) {
return (master);
}

View File

@@ -0,0 +1,71 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../../cfg";
/**
* @return {Object}
*/
export default function ShopData() {
let buffer = ({
"response_type": 5,
"unknown2": {
"unknown1": "1",
"items": [
{
"item_id": "pgorelease.pokeball.100",
"currency_to_buy": {
"name": "POKECOIN",
"amount": 460
},
"yields_item": {
"count": 100
},
"tags": [
{
"key": "CATEGORY",
"value": "ITEMS"
},
{
"key": "SORT",
"value": "2"
}
]
},
{
"item_id": "pgorelease.pokecoin.100",
"is_iap": true,
"yields_currency": {
"name": "POKECOIN",
"amount": 100
},
"tags": [
{
"key": "CATEGORY",
"value": "POKECOINS"
},
{
"key": "SORT",
"value": "1"
}
],
"unknown7": 1
}
],
"player_currencies": [
{
"name": "POKECOIN"
},
{
"name": "STARDUST",
"amount": 7681
}
],
"unknown4": "ZCgldzCNR+0pbImyvzykby/6+iA="
}
});
return (buffer);
}

View File

@@ -26,12 +26,17 @@ export SetAvatar from "./Responses.SetAvatar";
export SfidaActionLog from "./Responses.SfidaActionLog";
export CheckChallenge from "./Responses.CheckChallenge";
export Encounter from "./Responses.Encounter";
export CatchPokemon from "./Responses.CatchPokemon";
export NicknamePokemon from "./Responses.NicknamePokemon";
export UpgradePokemon from "./Responses.UpgradePokemon";
export EvolvePokemon from "./Responses.EvolvePokemon";
export SetFavoritePokemon from "./Responses.SetFavoritePokemon";
export ShopData from "./Responses.ShopData";
export AuthTicket from "./Envelopes.AuthTicket";
export ResponseEnvelope from "./Envelopes.ResponseEnvelope";
export ResponseEnvelopeAuth from "./Envelopes.ResponseEnvelope.Auth";

View File

@@ -25,9 +25,10 @@ class Player {
constructor(obj) {
this.uid = -1;
this.owner_id = -1;
this.email = null;
this.username = "undefined";
this.username = null;
this.latitude = 0;
this.longitude = 0;
@@ -37,6 +38,7 @@ class Player {
this.send_push_notifications = false;
this.exp = 0;
this.level = 0;
this.stardust = 0;
this.pokecoins = 0;
@@ -53,6 +55,36 @@ class Player {
this.gender = 0;
this.backpack = 0;
this.items = {
poke_ball: 0,
great_ball: 0,
ultra_ball: 0,
master_ball: 0,
potion: 0,
super_potion: 0,
hyper_potion: 0,
max_potion: 0,
revive: 0,
max_revive: 0,
lucky_egg: 0,
incense_ordinary: 0,
incense_spicy: 0,
incense_cool: 0,
incense_floral: 0,
troy_disk: 0,
razz_berry: 0,
bluk_berry: 0,
nanab_berry: 0,
wepar_berry: 0,
pinap_berry: 0,
incubator_basic: 0,
incubator_basic_unlimited: 0,
pokemon_storage_upgrade: 0,
storage_upgrade: 0
};
this.party = [];
this.tutorial_state = [];
this.badges = null;
@@ -77,6 +109,8 @@ class Player {
this.loggedIn = obj.loggedIn || false;
this.authenticated = false;
this.authentications = 0;
}
/**
@@ -105,10 +139,18 @@ class Player {
if (this.hasOwnProperty(key)) {
if (key === "send_marketing_emails" || key === "send_push_notifications") {
this[key] = !!obj[key];
} else {
}
else {
this[key] = obj[key];
}
}
else if (key.substring(0, 5) === "item_") {
let name = key.substring(5, key.length);
this.items[name] = obj[key];
}
else if (key === "id") {
this.owner_id = obj[key];
}
};
}
@@ -151,6 +193,19 @@ class Player {
}
/**
* @param {String} name
* @return {Boolean}
*/
export function validPlayerName(name) {
return !(
name === null ||
name === void 0 ||
typeof name === "string" &&
name.length <= 1
);
}
/**
* @param {Player} player
*/
@@ -254,17 +309,44 @@ export function removePlayer(player) {
}
/**
* @param {String} name
* @param {String} pkmn
*/
export function spawnPkmnAtPlayer(name, pkmn, amount) {
if (!this.validPlayerName(name)) {
this.print(`Invalid player name!`, 31);
return void 0;
}
let spawn = null;
let player = this.getPlayerByName(name);
if (player !== null) {
let index = 0;
while (++index < amount) {
spawn = {
pokemon_id: pkmn.toUpperCase(),
cp: Math.random() * 1e3 << 0,
encounter_id: Math.random() * 1e5 << 0,
latitude: player.latitude + parseFloat((Math.random() / 1e3).toFixed(5)),
longitude: player.longitude + parseFloat((Math.random() / 1e3).toFixed(5))
};
this.wild_pokemons.push(spawn);
};
this.print(`Spawned ${amount}x ${pkmn}'s to ${name} at ${spawn.latitude.toFixed(7)}:${spawn.longitude.toFixed(7)}!`);
}
else this.print(`Failed to spawn ${pkmn} to player ${name}!`, 31);
}
/**
* @param {String} name
*/
export function kickPlayer(name) {
if (
name === null ||
name === void 0 ||
typeof name === "string" &&
name.length <= 1
) {
if (!this.validPlayerName(name)) {
this.print(`Invalid player name!`, 31);
return void 0;
}
@@ -301,7 +383,9 @@ export function removeAllPlayers() {
export function savePlayer(player) {
return new Promise((resolve) => {
if (player.authenticated) {
this.updateUser(player).then(resolve);
this.updateUser(player).then(() => {
this.updateUserItems(player).then(resolve);
});
}
});
}
@@ -338,10 +422,14 @@ export function forwardPlayer(player) {
export function loginPlayer(player) {
return new Promise((resolve) => {
this.getUserByEmail(player.email).then((doc) => {
player.updateByObject(doc);
let buffer = GetPlayer(player);
resolve(buffer);
this.getUserByEmail(player.email).then((user) => {
user = user[0];
this.getPkmnByColumn("owner_id", user.id).then((party) => {
player.updateByObject(user);
player.party = party || [];
let buffer = GetPlayer(player);
resolve(buffer);
});
});
});

View File

@@ -38,6 +38,9 @@ export function processCommand(cmd, data) {
var length = this.clients.length;
this.print(`Saved ${length} player${length === 1 ? "": "s"} into database!`);
break;
case "/spawn":
this.spawnPkmnAtPlayer(data[1], data[2], data[3] || 1);
break;
case "/update":
eval(fs.readFileSync("update.js", "utf8"));
break;

View File

@@ -8,11 +8,10 @@ import CFG from "../cfg";
import {
ResponseEnvelope,
AuthTicket
AuthTicket,
ShopData
} from "./packets";
const REQUEST = proto.Networking.Requests.RequestType;
/**
* @param {Request} req
* @param {Response} res
@@ -52,22 +51,6 @@ export function routeRequest(req, res) {
}
/**
* @param {Request} req
* @return {String}
*/
export function getRequestType(req) {
for (let key in REQUEST) {
if (REQUEST[key] === req.request_type) {
return (key);
}
};
return ("INVALID");
}
export function parseProtobuf(buffer, path) {
try {
return POGOProtos.parseWithUnknown(buffer, path);
@@ -104,10 +87,7 @@ export function onRequest(req) {
let request = this.parseProtobuf(req.body, "POGOProtos.Networking.Envelopes.RequestEnvelope");
if (!request.requests.length) {
this.print("Received invalid request!", 31);
return void 0;
}
request.requests = request.requests || [];
if (CFG.DEBUG_LOG_REQUESTS) {
console.log("#####");
@@ -121,8 +101,21 @@ export function onRequest(req) {
return void 0;
}
this.processRequests(player, request.requests).then((answer) => {
let msg = this.envelopResponse(1, request.request_id, answer, !!request.auth_ticket, request);
if (!request.requests.length) {
// send shop data
if (request.unknown6 && request.unknown6.request_type === 6) {
let msg = this.envelopResponse(1, [], request, !!request.auth_ticket, true);
player.sendResponse(msg);
}
// otherwise invalid
else {
this.print("Received invalid request!", 31);
return void 0;
}
}
this.processRequests(player, request.requests).then((returns) => {
let msg = this.envelopResponse(1, returns, request, !!request.auth_ticket, false);
if (CFG.DEBUG_DUMP_TRAFFIC) {
this.dumpTraffic(req.body, msg);
}
@@ -133,18 +126,33 @@ export function onRequest(req) {
/**
* @param {Number} status
* @param {Long} id
* @param {Array} response
* @param {Array} returns
* @param {Request} req
* @param {Boolean} auth
* @param {Boolean} shop
* @return {Buffer}
*/
export function envelopResponse(status, id, response, auth, req) {
export function envelopResponse(status, returns, req, auth, shop) {
let buffer = req;
delete buffer.requests;
buffer.returns = response;
buffer.returns = returns;
if (auth) buffer.auth_ticket = AuthTicket();
if (shop) buffer.unknown6 = [ShopData()];
if (buffer.unknown6 && !shop) {
buffer.unknown6 = [{
"response_type": 6,
"unknown2": {
"unknown1": "1",
"items": [],
"player_currencies": []
}
}];
}
buffer.status_code = 1;

View File

@@ -1,4 +1,5 @@
import proto from "./proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
@@ -10,6 +11,7 @@ import {
DownloadRemoteConfigVersion,
GetPlayerProfile,
ItemTemplates,
GetPlayer,
GetAssetDigest,
GetDownloadUrls,
GetMapObjects,
@@ -21,11 +23,13 @@ import {
MarkTutorialComplete,
LevelUpRewards,
Encounter,
CatchPokemon,
NicknamePokemon,
UpgradePokemon,
EvolvePokemon,
SetFavoritePokemon,
ClaimCodeName
ClaimCodeName,
CheckChallenge
} from "./packets";
import { _toCC } from "./utils";
@@ -58,14 +62,23 @@ export function processResponse(player, req) {
try {
switch (req.request_type) {
case "GET_PLAYER":
player.authentications++;
if (player.authentications >= 2) {
buffer = GetPlayer(player);
resolve(buffer);
return void 0;
}
this.forwardPlayer(player).then((res) => resolve(res));
return void 0;
break;
case "CHECK_CHALLENGE":
buffer = CheckChallenge();
break;
case "GET_HATCHED_EGGS":
buffer = GetHatchedEggs();
break;
case "GET_INVENTORY":
buffer = GetInventory(msg);
buffer = GetInventory(player);
break;
case "CHECK_AWARDED_BADGES":
buffer = CheckAwardedBadges();
@@ -74,7 +87,7 @@ export function processResponse(player, req) {
buffer = DownloadSettings();
break;
case "DOWNLOAD_ITEM_TEMPLATES":
buffer = ItemTemplates();
buffer = ItemTemplates(this.master);
break;
case "DOWNLOAD_REMOTE_CONFIG_VERSION":
buffer = DownloadRemoteConfigVersion(msg);
@@ -87,7 +100,7 @@ export function processResponse(player, req) {
break;
case "GET_MAP_OBJECTS":
player.updatePosition(msg);
buffer = GetMapObjects(player, msg);
buffer = GetMapObjects(player, this.wild_pokemons, msg);
this.savePlayer(player).then(() => {
resolve(buffer);
});
@@ -131,7 +144,11 @@ export function processResponse(player, req) {
buffer = FortDetails(msg);
break;
case "FORT_SEARCH":
buffer = FortSearch();
buffer = FortSearch(player);
this.updateUserItems(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "SET_CONTACT_SETTINGS":
player.updateContactSettings(msg);
@@ -142,7 +159,31 @@ export function processResponse(player, req) {
return void 0;
break;
case "ENCOUNTER":
buffer = Encounter(msg);
buffer = Encounter(this.getEncounterPkmn(msg).pkmn, msg);
break;
case "CATCH_POKEMON":
let encounter = this.getEncounterPkmn(msg);
let result = CatchPokemon(encounter.pkmn, player, msg);
// save pkmn into player party
if (result.status !== "CATCH_MISSED") {
result.pkmn.owner_id = player.owner_id;
player.exp += 100;
player.stardust += 100;
this.wild_pokemons.splice(encounter.index, 1);
this.createOwnedPokemon(result.pkmn).then(() => {
// make sure it got saved, also get db id
this.getQueryByColumnFromTable("creation_time_ms", result.pkmn.creation_time_ms, CFG.MYSQL_OWNED_PKMN_TABLE).then((query) => {
player.party.push(query[0]);
result.buffer.captured_pokemon_id = query[0].id;
result = POGOProtos.serialize(result.buffer, "POGOProtos.Networking.Responses.CatchPokemonResponse");
resolve(result);
});
});
}
else {
resolve(POGOProtos.serialize(result, "POGOProtos.Networking.Responses.CatchPokemonResponse"));
}
return void 0;
break;
case "NICKNAME_POKEMON":
buffer = NicknamePokemon(msg);
@@ -168,4 +209,25 @@ export function processResponse(player, req) {
});
}
export function getEncounterPkmn(req) {
let ii = 0;
let length = this.wild_pokemons.length;
let pkmn = null;
for (; ii < length; ++ii) {
pkmn = this.wild_pokemons[ii];
if (pkmn.encounter_id === parseInt(req.encounter_id)) {
break;
}
};
return ({
pkmn: pkmn,
index: ii
});
}

View File

@@ -2,6 +2,7 @@ import fs from "fs";
import fse from "fs-extra";
import pogo from "pogo-asset-downloader";
import proto from "./proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
@@ -27,7 +28,7 @@ export function setup() {
this.print(`Downloaded assets are valid! Proceeding..`);
this.asset = this.parseAssetDigest();
this.master = this.parseGameMaster();
this.master = POGOProtos.serialize(this.parseGameMaster(), "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
this.setupDatabaseConnection().then(() => {
if (CFG.PORT < 1) {
@@ -58,7 +59,13 @@ export function validateAssets() {
return new Promise((resolve, reject) => {
// validate asset digest
// validate asset digests
/*if (!this.fileExists(CFG.DUMP_ASSET_PATH + "asset_digest_ios")) {
return reject("File asset_digest_ios");
}
if (!this.fileExists(CFG.DUMP_ASSET_PATH + "asset_digest_android")) {
return reject("File asset_digest_android");
}*/
if (!this.fileExists(CFG.DUMP_ASSET_PATH + "asset_digest")) {
return reject("File asset_digest");
}
@@ -110,20 +117,69 @@ export function onFirstRun(resolve) {
username: CFG.DOWNLOAD_USERNAME,
password: CFG.DOWNLOAD_PASSWORD
}).then((res) => {
let asset = res.asset;
this.print(`Dumping asset digest..`, 35);
let client = res.client;
// create data dir, if login successed
fse.ensureDirSync(CFG.DUMP_ASSET_PATH);
fs.writeFileSync(CFG.DUMP_ASSET_PATH + "asset_digest", res.asset.toBuffer());
// write game master
fs.writeFileSync(CFG.DUMP_ASSET_PATH + "game_master", res.master.toBuffer());
this.dumpPkmnModels(() => {
resolve();
// get and write asset digests
this.dumpAssetDigests(client).then(() => {
// dump pkmn models
this.dumpPkmnModels(() => {
resolve();
});
});
}).catch((e) => {
this.print(e, 31);
});
}
export function dumpAssetDigests(client) {
this.print(`Dumping asset digests..`, 35);
let platforms = [
{
name: "ios",
platform: 1,
manufacturer: "Apple",
model: "iPhone8,1",
locale: "",
version: 3300
},
{
name: "android",
platform: 2,
manufacturer: "LGE",
model: "Nexus 5",
locale: "",
version: 3300
}
];
return new Promise((resolve, reject) => {
let ii = 0;
let index = 0;
for (; ii < platforms.length; ++ii) {
let key = platforms[ii];
client.getAssetDigest(
key.platform,
key.manufacturer,
key.model,
key.locale,
key.version
).then((asset) => {
this.print(`Dumping ${key.name} asset digest..`, 35);
fs.writeFileSync(CFG.DUMP_ASSET_PATH + "asset_digest_" + key.name, asset.toBuffer());
if (++index >= platforms.length) {
resolve();
}
});
};
});
}
export function dumpPkmnModels(resolve) {
let limit = CFG.MAX_POKEMON_NATIONAL_ID;