Initial commit

This commit is contained in:
Felix
2016-08-26 15:38:13 +02:00
parent a500b0c6e1
commit 59c2bc0767
74 changed files with 1100 additions and 3390 deletions

5
.gitignore vendored
View File

@@ -1,6 +1,3 @@
node_modules/
scripts/
logs/
data/
cfg.js
npm-debug.*
data/

16
.help
View File

@@ -1,8 +1,8 @@
clients : How many players are connected
exit : Exit the server
update : Update the server
kick [PlayerName] : Kick player by username
kickall : Kick all players
clear : Clear the server console
save : Save all players into database
spawn [PlayerName] [PokemonName] [Amount] : Spawn pokemons at specific player
clients : How many players are connected
exit : Exit the server
update : Update the server
kick [Username] : Kick player by username
kickall : Kick all players
clear : Clear the server console
save : Save all players into database
spawn [Username] [Pkmn] [Amount] : Spawn pokemons at users position

2
install-windows.bat vendored Normal file
View File

@@ -0,0 +1,2 @@
set LIBPROTOBUF=%CD%\protobuf
npm install node-protobuf && npm install

View File

@@ -1,6 +1,6 @@
{
"name": "POGOServer",
"version": "0.4.9",
"version": "0.5.0",
"description": "",
"repository": {
"type": "git",
@@ -9,7 +9,7 @@
"scripts": {
"test": "echo \"Error: no test specified\"",
"babel-node": "babel-node --presets=es2015",
"start": "nodemon --ignore tmp/ --ignore data/ --ignore logs/ --exec npm run babel-node -- ./src/index.js"
"start": "npm run babel-node -- ./src/index.js"
},
"engines": {
"node": ">= 6.x",
@@ -21,17 +21,10 @@
"babel-cli": "^6.11.4",
"babel-preset-es2015": "^6.13.1",
"babel-preset-stage-0": "^6.5.0",
"nodemon": "^1.7.1",
"mongodb": "^2.2.5",
"fs-extra": "^0.30.0",
"mysql": "^2.11.1",
"jwt-decode": "^2.1.0",
"long": "^3.2.0",
"pogo-asset-downloader": "^0.3.1",
"node-pogo-protos": "^1.3.0",
"path": "^0.12.7",
"directory-tree": "^1.1.0",
"nodegit": "^0.14.1",
"fs-extra": "^0.30.0",
"pokemongo-protobuf": "^1.11.0",
"pcrypt": "git+https://github.com/laverdet/pcrypt.git"
},

2
run-windows.bat vendored
View File

@@ -1,2 +1,2 @@
npm install && npm run start
npm run start
pause

View File

@@ -20,8 +20,6 @@ export function cycle() {
if (this.passedTicks <= 0) return void 0;
this.updatePlayers();
this.resetTimers();
return void 0;
@@ -49,7 +47,7 @@ export function resetTimers() {
this.saveTick++;
// Save interval
if (this.saveTick >= CFG.SAVE_INTERVAL) {
this.saveAllPlayers();
//this.saveAllPlayers();
this.saveTick = 0;
}
return void 0;
@@ -57,17 +55,20 @@ export function resetTimers() {
export function playerTimeoutTick() {
let client = null;
let player = null;
let maxTimeout = CFG.PLAYER_CONNECTION_TIMEOUT;
let ii = 0, length = this.clients.length;
let players = this.world.players;
let ii = 0;
let length = players.length;
for (; ii < length; ++ii) {
client = this.clients[ii];
if (this.time - client.timeout >= maxTimeout) {
this.print(`${client.remoteAddress} timed out`, 34);
this.savePlayer(client);
this.removePlayer(client);
player = players[ii];
if (this.time - player.timeout >= maxTimeout) {
this.print(`${player.remoteAddress} timed out`, 34);
this.savePlayer(player);
this.removePlayer(player);
}
};

View File

@@ -1,7 +1,7 @@
import fs from "fs";
import CFG from "../../cfg";
export function createTableIfNoExists(name) {
export function createTableIfNotExists(name) {
return new Promise((resolve) => {
this.db.instance.query(`SHOW TABLES LIKE '${name}';`, (e, rows, fields) => {
if (e) console.log(e);
@@ -33,7 +33,7 @@ export function createTable(name) {
this.print(`Creating table ${name}`, 36);
let query = `
CREATE TABLE ${name} (
CREATE TABLE IF NOT EXISTS ${name} (
${fs.readFileSync(__dirname + "/tables/" + name + ".table", "utf8")}
) ENGINE=InnoDB;
`;

View File

@@ -27,39 +27,4 @@ export function deleteQueryByColumnFromTable(column, value, table) {
else resolve(void 0);
});
});
}
/**
* @param {String} column
* @param {String} value
*/
export function getPkmnByColumn(column, value) {
return new Promise((resolve) => {
this.getQueryByColumnFromTable(column, value, CFG.MYSQL_OWNED_PKMN_TABLE).then((query) => {
resolve(query || []);
});
});
}
/**
* @param {String} column
* @param {String} value
*/
export function getUserByColumn(column, value) {
return new Promise((resolve) => {
this.getQueryByColumnFromTable(column, value, CFG.MYSQL_USERS_TABLE).then((query) => {
resolve(query);
});
});
}
/**
* @param {String} email
*/
export function getUserByEmail(email) {
return new Promise((resolve) => {
this.getQueryByColumnFromTable("email", email, CFG.MYSQL_USERS_TABLE).then((query) => {
resolve(query);
});
});
}
}

View File

@@ -1,9 +1,8 @@
import fs from "fs";
import mysql from "mysql";
import CFG from "../../cfg";
export function setupConnection() {
export function setupDatabaseConnection() {
let connection = mysql.createConnection({
host : CFG.MYSQL_HOST_IP,
@@ -17,12 +16,12 @@ export function setupConnection() {
connection.connect((error) => {
if (error) {
this.print("MySQL " + error, 31);
this.retry("Retrying again in ", () => this.setupConnection().then(resolve), 5);
this.retry("Retrying again in ", () => this.setupDatabaseConnection().then(resolve), 5);
return void 0;
}
this.db.instance = connection;
this.createTableIfNoExists(CFG.MYSQL_USERS_TABLE).then(() => {
this.createTableIfNoExists(CFG.MYSQL_OWNED_PKMN_TABLE).then(() => {
this.createTableIfNotExists(CFG.MYSQL_USERS_TABLE).then(() => {
this.createTableIfNotExists(CFG.MYSQL_OWNED_PKMN_TABLE).then(() => {
this.print(`\x1b[36;1mMySQL\x1b[0m\x1b[32;1m connection established\x1b[0m`);
resolve();
});
@@ -30,7 +29,7 @@ export function setupConnection() {
});
connection.on("error", (error) => {
this.print("MySQL " + error, 31);
this.retry("Trying to reconnect in ", () => this.setupConnection().then(resolve), 5);
this.retry("Trying to reconnect in ", () => this.setupDatabaseConnection().then(resolve), 5);
});
});
@@ -43,103 +42,4 @@ export function closeConnection(resolve) {
this.db.instance.end(() => {
resolve();
});
}
/**
* @param {Object} obj
*/
export function createUser(obj) {
let query = this.getUserQuery("INSERT INTO", "");
let data = this.getUserQueryData(obj);
return new Promise((resolve) => {
this.db.instance.query(query, data, (e) => {
if (e) this.print(e, 31);
else resolve();
});
});
}
/**
* @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
*/
export function deleteOwnedPokemon(id) {
return new Promise((resolve) => {
this.deleteQueryByColumnFromTable("id", id, CFG.MYSQL_OWNED_PKMN_TABLE).then(() => {
resolve();
});
});
}
/**
* @param {Player} player
*/
export function updateUser(player) {
let query = this.getUserQuery("UPDATE", "WHERE email=? LIMIT 1");
let data = this.getUserQueryData(player);
return new Promise((resolve) => {
this.db.instance.query(query, data, resolve);
});
}
/**
* @param {Player} player
*/
export function updateUserItems(player) {
let query = this.getUserItemQuery("UPDATE", "WHERE email=? LIMIT 1");
let data = this.getUserItemQueryData(player);
return new Promise((resolve) => {
this.db.instance.query(query, data, resolve);
});
}
/**
* @param {Player} player
*/
export function updateUserParty(player) {
let pkmn = null;
let data = null;
let query = this.getOwnedPkmnQuery("UPDATE", "WHERE id=? AND owner_id=? LIMIT 1");
return new Promise((resolve) => {
let ii = 0;
let index = 0;
let length = player.party.length;
// dont go on if party empty
if (!length) return resolve();
for (; ii < length; ++ii) {
pkmn = player.party[ii];
data = this.getOwnedPkmnQueryData(pkmn);
data.push(pkmn.id, player.owner_id);
this.db.instance.query(query, data, () => {
if (++index >= length) resolve();
});
};
});
}

View File

@@ -1,8 +0,0 @@
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,8 +0,0 @@
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,25 +1,25 @@
id int(11) NOT NULL AUTO_INCREMENT,
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,
username varchar(16) NOT NULL,
email varchar(32) NOT NULL,
exp int(11) NOT NULL,
level smallint(11) NOT NULL,
stardust int(11) NOT NULL,
pokecoins int(11) NOT NULL,
team tinyint(11) NOT NULL,
latitude double NOT NULL,
longitude double NOT NULL,
altitude int(255) NOT NULL,
altitude double 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,
avatar_skin tinyint(1) NOT NULL,
avatar_hair tinyint(1) NOT NULL,
avatar_shirt tinyint(1) NOT NULL,
avatar_pants tinyint(1) NOT NULL,
avatar_hat tinyint(1) NOT NULL,
avatar_shoes tinyint(1) NOT NULL,
avatar_eyes tinyint(1) NOT NULL,
avatar_gender tinyint(1) NOT NULL,
avatar_backpack tinyint(1) NOT NULL,
item_poke_ball int(11) NOT NULL,
item_great_ball int(11) NOT NULL,
item_ultra_ball int(11) NOT NULL,
@@ -45,4 +45,10 @@ 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,
tutorial_legal_screen tinyint(1) NOT NULL,
tutorial_avatar_selection tinyint(1) NOT NULL,
tutorial_pokemon_capture tinyint(1) NOT NULL,
tutorial_name_selection tinyint(1) NOT NULL,
tutorial_first_time_exp tinyint(1) NOT NULL,
candies text(11) NOT NULL,
PRIMARY KEY (id)

75
src/dump.js Normal file
View File

@@ -0,0 +1,75 @@
import fse from "fs-extra";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
/**
* @param {Request} req
* @param {Array} res
* @return {Object}
*/
export function decode(req, res) {
// clone
req = JSON.parse(JSON.stringify(req));
res = JSON.parse(JSON.stringify(res));
// dont decode unknown6, since it bloats the file size
delete req.unknown6;
// decode requests
for (let request of req.requests) {
let key = _toCC(request.request_type);
let msg = request.request_message;
if (msg) {
let proto = `POGOProtos.Networking.Requests.Messages.${key}Message`;
request.request_message = this.parseProtobuf(new Buffer(msg.data), proto);
}
};
// decode responses
let index = 0;
for (let resp of res) {
let key = _toCC(req.requests[index].request_type);
let msg = new Buffer(resp);
let proto = `POGOProtos.Networking.Responses.${key}Response`;
res[index] = this.parseProtobuf(msg, proto);
index++;
};
// clone again to build response out of it
let req2 = JSON.parse(JSON.stringify(req));
// build res base out of req
delete req2.requests;
req2.returns = res;
req2.status_code = 1;
return ({
req: req,
res: res
});
}
/**
* @param {Request} req
* @param {Response} res
*/
export function dumpTraffic(req, res) {
let decoded = this.decode(req, res);
let out = {
Request: decoded.req,
Response: decoded.res
};
try {
let decoded = JSON.stringify(out, null, 2);
fse.outputFileSync(CFG.DEBUG_DUMP_PATH + Date.now(), decoded);
} catch (e) {
this.print("Dump traffic: " + e, 31);
}
}

39
src/http.js Normal file
View File

@@ -0,0 +1,39 @@
import http from "http";
import CFG from "../cfg";
/**
* @return {HTTP}
*/
export function createHTTPServer() {
let server = http.createServer((req, res) => {
if (this.world.isFull()) {
this.print(`Server is full! Refused ${req.headers.host}`, 31);
return void 0;
}
let chunks = [];
req.on("data", (chunk) => {
chunks.push(chunk);
});
req.on("end", () => {
let buffer = Buffer.concat(chunks);
req.body = buffer;
this.world.getPlayerByRequest(req, res).then((player) => {
this.routeRequest(player, req, res);
});
});
});
server.listen(CFG.PORT);
return (server);
}
export function shutdown() {
this.socket.close(() => {
this.print("Closed http server!", 33);
this.closeConnection(() => {
this.print("Closed database connection!", 33);
this.print("Server shutdown!", 31);
setTimeout(() => process.exit(1), 2e3);
});
});
}

View File

@@ -1,9 +1,7 @@
import fs from "fs";
import os from "os";
import fse from "fs-extra";
import http from "http";
import proto from "./proto";
import EventEmitter from "events";
import POGOProtos from "pokemongo-protobuf";
import {
inherit,
@@ -12,10 +10,13 @@ import {
import CFG from "../cfg";
import World from "./models/World";
import * as _api from "./api";
import * as _dump from "./dump";
import * as _http from "./http";
import * as _setup from "./setup";
import * as _cycle from "./cycle";
import * as _player from "./player";
import * as _request from "./request";
import * as _response from "./response";
import * as _process from "./process";
@@ -60,14 +61,13 @@ export default class GameServer extends EventEmitter {
this.timeoutTick = 0;
this.passedTicks = 0;
this.clients = [];
this.wild_pokemons = [];
this.initAPI();
if (CFG.GREET) this.greet();
this.print(`Booting Server v${require("../package.json").version}...`, 33);
this.print(`Booting Server v${require("../package.json").version}-dev`, 33);
this.world = new World(this);
this.setup();
@@ -85,84 +85,6 @@ export default class GameServer extends EventEmitter {
}
}
clientAlreadyConnected(client) {
let remoteAddress = client.headers.host;
let ii = 0, length = this.clients.length;
for (; ii < length; ++ii) {
if (this.clients[ii].remoteAddress === remoteAddress) {
return (true);
}
};
return (false);
}
/**
* @return {HTTP}
*/
createHTTPServer() {
let server = http.createServer((req, res) => {
if (this.clients.length >= CFG.MAX_CONNECTIONS) {
this.print(`Server is full! Refused ${req.headers.host}`, 31);
return void 0;
}
let player = null;
if (this.clientAlreadyConnected(req)) player = this.getPlayerByRequest(req);
else player = this.addPlayer(req, res);
let chunks = [];
req.on("data", (chunk) => {
chunks.push(chunk);
});
req.on("end", () => {
let buffer = Buffer.concat(chunks);
req.body = buffer;
player.updateResponse(res);
this.routeRequest(req, res);
});
});
server.listen(CFG.PORT);
return (server);
}
setupDatabaseConnection() {
return new Promise((resolve) => {
let name = String(CFG.DATABASE_TYPE).toUpperCase();
switch (name) {
case "MYSQL":
inherit(GameServer, _mysql);
this.setupConnection().then(resolve);
break;
default:
this.print("Invalid database connection type!", 31);
return void 0;
break;
};
});
}
shutdown() {
this.socket.close(() => {
this.print("Closed http server!", 33);
this.closeConnection(() => {
this.print("Closed database connection!", 33);
this.print("Server shutdown!", 31);
setTimeout(() => process.exit(1), 2e3);
});
});
}
/**
* @param {String} msg
* @param {Number} color
@@ -174,87 +96,23 @@ export default class GameServer extends EventEmitter {
/**
* @param {String} msg
* @param {Function} func
* @param {Function} fn
* @param {Number} timer
*/
retry(msg, func, timer) {
retry(msg, fn, timer) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
this.print(`${msg}${timer}s`, 33, true);
if (timer >= 1) setTimeout(() => this.retry(msg, func, --timer), 1e3);
if (timer >= 1) setTimeout(() => this.retry(msg, fn, --timer), 1e3);
else {
process.stdout.write("\n");
func();
fn();
}
}
/**
* @param {Request} req
* @param {Array} res
* @return {Object}
* @return {String}
*/
decode(req, res) {
// clone
req = JSON.parse(JSON.stringify(req));
res = JSON.parse(JSON.stringify(res));
// dont decode unknown6, since it bloats the file size
delete req.unknown6;
// decode requests
for (let request of req.requests) {
let key = _toCC(request.request_type);
let msg = request.request_message;
if (msg) {
let proto = `POGOProtos.Networking.Requests.Messages.${key}Message`;
request.request_message = this.parseProtobuf(new Buffer(msg.data), proto);
}
};
// decode responses
let index = 0;
for (let resp of res) {
let key = _toCC(req.requests[index].request_type);
let msg = new Buffer(resp);
let proto = `POGOProtos.Networking.Responses.${key}Response`;
res[index] = this.parseProtobuf(msg, proto);
index++;
};
// clone again to build response out of it
let req2 = JSON.parse(JSON.stringify(req));
// build res base out of req
delete req2.requests;
req2.returns = res;
req2.status_code = 1;
return ({
req: req,
res: res
});
}
dumpTraffic(req, res) {
let decoded = this.decode(req, res);
let out = {
Request: decoded.req,
Response: decoded.res
};
try {
let decoded = JSON.stringify(out, null, 2);
fse.outputFileSync(CFG.DEBUG_DUMP_PATH + Date.now(), decoded);
} catch (e) {
this.print("Dump traffic: " + e, 31);
}
}
getLocalIPv4() {
let address = null;
let interfaces = os.networkInterfaces();
@@ -264,15 +122,32 @@ export default class GameServer extends EventEmitter {
return (address);
}
directoryExists(directory) {
/**
* @param {Buffer} buffer
* @param {String} schema
*/
parseProtobuf(buffer, schema) {
try {
fs.statSync(directory);
return true;
} catch(e) {
return false;
return POGOProtos.parseWithUnknown(buffer, schema);
} catch (e) {
this.print(e, 31);
}
}
/**
* @param {Request} req
*/
parseSignature(req) {
let key = pcrypt.decrypt(req.unknown6.unknown2.encrypted_signature);
return (
POGOProtos.parseWithUnknown(key, "POGOProtos.Networking.Envelopes.Signature")
);
}
/**
* @param {String} path
* @return {Boolean}
*/
fileExists(path) {
try {
fs.statSync(path);
@@ -288,9 +163,10 @@ export default class GameServer extends EventEmitter {
}
inherit(GameServer, _dump);
inherit(GameServer, _http);
inherit(GameServer, _setup);
inherit(GameServer, _cycle);
inherit(GameServer, _player);
inherit(GameServer, _request);
inherit(GameServer, _response);
inherit(GameServer, _process);
@@ -299,10 +175,9 @@ inherit(GameServer, _mysql_get);
inherit(GameServer, _mysql_query);
inherit(GameServer, _mysql_create);
(() => {
((Server) => {
const server = new Server();
const server = new GameServer();
process.openStdin().addListener("data", (data) => {
server.stdinInput(data);
@@ -312,4 +187,4 @@ inherit(GameServer, _mysql_create);
server.uncaughtException(data);
});
})(GameServer);
})();

6
src/master.js Normal file
View File

@@ -0,0 +1,6 @@
/**
* Global shared parsed
* game master file
* @type {GameMaster}
*/
export let GAME_MASTER = null;

View File

@@ -0,0 +1,63 @@
/**
* @class GameMaster
*/
export default class GameMaster {
/**
* @param {Buffer} buffer
* @constructor
*/
constructor(buffer) {
this.settings = this.buildSettings();
this.buffer = buffer;
this.parse();
}
parse() {
let ii = 0;
let length = 0;
let item = null;
let items = this.buffer.item_templates;
length = items.length;
for (; ii < length; ++ii) {
item = items[ii];
this.parseKey(item, item.template_id);
};
}
/**
* @param {Object} item
* @param {String} key
*/
parseKey(item, key) {
if (key in this.settings) {
this.settings[key] = item;
}
}
/**
* @return {Object}
*/
buildSettings() {
let settings = {
"PLAYER_LEVEL_SETTINGS": null
};
return (settings);
}
getPlayerSettings() {
return (
this.settings["PLAYER_LEVEL_SETTINGS"].player_level
);
}
}

View File

@@ -0,0 +1,123 @@
/**
* @class Avatar
*/
export default class Avatar {
/** @constructor */
constructor() {
this._skin = 0;
this._hair = 0;
this._shirt = 0;
this._pants = 0;
this._hat = 0;
this._shoes = 0;
this._eyes = 0;
this._gender = 0;
this._backpack = 0;
}
/**
* @param {Number} value
* @param {Number} a
* @param {Number} b
* @return {Boolean}
*/
between(value, a, b) {
return (
value >= a && value <= b
);
}
// skin
get skin() {
return (this._skin);
}
set skin(value) {
if (this.between(value, 0, 3)) {
this.skin = value;
}
}
// hair
get hair() {
return (this._hair);
}
set hair(value) {
if (this.between(value, 0, 5)) {
this._hair = value;
}
}
// shirt
get shirt() {
return (this._shirt);
}
set shirt(value) {
if (this.between(value, 0, 3)) {
this._shirt = value;
}
}
// pants
get pants() {
return (this._pants);
}
set pants(value) {
if (this.between(value, 0, 2)) {
this._pants = value;
}
}
// hat
get hat() {
return (this._hat);
}
set hat(value) {
if (this.between(value, 0, 4)) {
this._hat = value;
}
}
// shoes
get shoes() {
return (this._shoes);
}
set shoes(value) {
if (this.between(value, 0, 6)) {
this._shoes = value;
}
}
// eyes
get eyes() {
return (this._eyes);
}
set eyes(value) {
if (this.between(value, 0, 4)) {
this._eyes = value;
}
}
// gender
get gender() {
return (this._gender);
}
set gender(value) {
if (this.between(value, 0, 1)) {
this._gender = value;
}
}
// backpack
get backpack() {
return (this._backpack);
}
set backpack(value) {
if (this.between(value, 0, 5)) {
this._backpack = value;
}
}
}

View File

@@ -0,0 +1,71 @@
/**
* @class CandyBag
*/
export default class CandyBag {
/** @constructor */
constructor() {
this.candies = [];
}
getCandyByDexNumber(dex) {
let candies = this.candies;
let ii = 0;
let length = candies.length;
for (; ii < length; ++ii) {
if (candies[ii].dex === dex) {
return (candies[ii]);
}
};
return (null);
}
/**
* @param {String} str
*/
parseCandies(str) {
let result = null;
let seperator = ":";
let split = str.split(",");
let ii = 0;
let length = split.length;
for (; ii < length; ++ii) {
result = split[ii].split(seperator);
this.candies.push({
dex: result[0] << 0,
amount: result[1] << 0
});
};
}
/**
* @return {String}
*/
serializeCandies() {
let str = "";
let candies = this.candies;
let ii = 0;
let length = candies.length;
for (; ii < length; ++ii) {
str += candies[ii].dex + ":" + candies[ii].dex;
if (ii + 1 < length) str += ",";
};
return (str);
}
}

View File

@@ -0,0 +1,72 @@
import Candy from "./Candy";
/**
* @class Bag
*/
export default class Bag {
/** @constructor */
constructor() {
this.candies = new CandyBag();
this.stardust = 0;
this.pokecoins = 0;
this.pokeBall = 0;
this.greatBall = 0;
this.ultraBall = 0;
this.masterBall = 0;
this.potion = 0;
this.superPotion = 0;
this.hyperPotion = 0;
this.maxPotion = 0;
this.revive = 0;
this.maxRevive = 0;
this.razzBerry = 0;
this.blukBerry = 0;
this.nanabBerry = 0;
this.weparBerry = 0;
this.pinapBerry = 0;
// premium shit
this.luckyEgg = 0;
this.troyDisk = 0;
this.incenseOrdinary = 0;
this.incenseSpicy = 0;
this.incenseCool = 0;
this.incenseFloral = 0;
this.incubatorBasic = 0;
this.incubatorBasicUnlimited = 0;
this.storageUpgrade = 0;
this.pkmnStorageUpgrade = 0;
}
/**
* @param {Number} dex
* @return {Object}
*/
getCandy(dex) {
return (
this.candies.getCandyByDexNumber(dex)
);
}
/**
* @param {Number} dex
* @param {Number} value
*/
updateCandyAmount(dex, value) {
let candy = this.getCandy(dex);
candy.amount += (value << 0);
}
}

View File

@@ -0,0 +1,91 @@
/**
* @class Info
*/
class Info {
/** @constructor */
constructor() {
this.lvl = 0;
this.exp = 0;
this.prevLvlExp = 0;
this.nextLvlExp = 0;
this.kmWalked = 0;
this.pkmnEncountered = 0;
this.uniquePokedexEntries = 0;
this.pkmnCaptured = 0;
this.pokeStopVisits = 0;
this.pokeballsThrown = 0;
this.eggsHatched = 0;
this.bigMagikarpCaught = 0;
this.pkmnDeployed = 0;
}
upgradeLevel() {
}
getLevelSettings() {
return (
this.owner.gameMaster("PLAYER_LEVEL_SETTINGS")
);
}
getMaximumLevel() {
return (
Object.keys(this.getLevelSettings().player_level).length
);
}
getCurrentLevel() {
let levels = this.getLevelSettings().required_experience;
for (let key in levels) {
if (levels[key] << 0 === this.nextLvlExp) {
return (key << 0);
}
};
return (1);
}
/**
* @param {Number} exp
*/
upgradeExp(exp) {
let levels = this.getLevelSettings().required_experience;
let maxLevel = this.getMaximumLevel();
let currentLevel = this.getCurrentLevel();
if (currentLevel + 1 <= maxLevel) {
this.lvl += 1;
this.exp += exp;
this.prevLvlExp = levels[this.lvl - 1];
this.nextLvlExp = levels[this.lvl + 1];
}
else {
this.exp += exp;
}
}
getPlayerInfo() {
return ({
player_stats: {
level: this.lvl,
experience: this.exp,
prev_level_xp: this.prevLvlExp,
next_level_xp: this.nextLvlExp,
km_walked: this.kmWalked,
pokemons_encountered: this.pkmnEncountered,
unique_pokedex_entries: this.uniquePokedexEntries,
pokemons_captured: this.pkmnCaptured,
poke_stop_visits: this.pokeStopVisits,
pokeballs_thrown: this.pokeballsThrown,
eggs_hatched: this.eggsHatched,
big_magikarp_caught: this.bigMagikarpCaught,
pokemon_deployed: this.pkmnDeployed
}
});
}
}

View File

@@ -0,0 +1,65 @@
/**
* @class Party
*/
class Party {
/** @constructor */
constructor() {
this.party = [];
}
addPkmn(obj) {
console.log(obj);
}
/**
* @param {Number} id
* @return {Number}
*/
getPkmnIndexById(id) {
for (let ii = 0; ii < this.party.length; ++ii) {
if (this.party[ii].id === id) return (ii);
};
return (-1);
}
/**
* @param {Number} id
* @return {Pokemon}
*/
getPkmnById(id) {
let index = this.getPkmnIndexById(id);
return (this.party[index]);
}
/**
* @param {Number} id
*/
deletePkmn(id) {
let index = this.getPkmnIndexById(id);
let pkmn = this.party[index];
if (pkmn) this.party.splice(index, 1);
}
/**
* @return {Number}
*/
getUniquePkmnCount() {
let ii = 0;
let dex = 0;
let amount = 0;
let length = this.party.length;
let array = [];
for (; ii < length; ++ii) {
dex = this.party[ii].dexNumber;
if (array.indexOf(dex) === -1) {
array.push(dex);
amount++;
}
};
return (amount);
}
}

View File

@@ -0,0 +1,33 @@
import Avatar from "./Avatar";
import MapObject from "../World/MapObject";
import { GAME_MASTER } from "../../master";
/**
* @class Player
*/
export default class Player extends MapObject {
/**
* @param {Object} obj
* @constructor
*/
constructor(obj) {
super(null);
this.request = obj.request;
this.response = obj.response;
this.authenticated = 0;
this.bag = new Bag(this);
this.info = new Info(this);
this.pary = new Party(this);
this.avatar = new Avatar(this);
this.pokedex = new Pokedex(this);
this.tutorial = new Tutorial(this);
}
}

View File

@@ -0,0 +1,7 @@
import POGOProtos from "pokemongo-protobuf";
export function GetPlayer() {
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerResponse"));
}

View File

@@ -0,0 +1,7 @@
import POGOProtos from "pokemongo-protobuf";
export function GetPlayerProfile() {
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerProfileResponse"));
}

View File

@@ -0,0 +1,28 @@
import Pokemon from "index";
import CaptureProbability from "CaptureProbability";
/**
* @class WildPokemon
*/
class WildPokemon extends Pokemon {
/**
* @param {Object} obj
* @constructor
*/
constructor(obj) {
super(obj);
this.encounterId = 0;
this.latitude = 0;
this.longitude = 0;
this.pokeball = 0;
this.spawnPoint = 0;
}
}

127
src/models/Pokemon/index.js Normal file
View File

@@ -0,0 +1,127 @@
import pokename from "pokename";
import MapObject from "../World/MapObject";
import {
validName
} from "../../utils";
/**
* @class Pokemon
*/
export default class Pokemon extends MapObject {
/**
* @param {Object} obj
* @constructor
*/
constructor(obj) {
this.id = 0;
this.dexNumber = 0;
this.owner = null;
this.level = 0;
this.cp = 0;
this.cpMultiplier = 0;
this.addCpMultiplier = 0;
this.stamina = 0;
this.staminaMax = 0;
this.move1 = 0;
this.move2 = 0;
this.attack = 0;
this.defence = 0;
this.height = 0;
this.weight = 0;
this.ivAttack = 0;
this.ivDefense = 0;
this.ivStamina = 0;
this.nickname = null;
this.favorite = 0;
this.init(obj);
}
/**
* @param {Object} obj
*/
init(obj) {
obj = obj || {};
for (let key in obj) {
if (this.hasOwnProperty(key)) {
this[key] = obj[key];
}
};
}
/**
* @param {Boolean} truth
*/
setFavorite(truth) {
this.favorite = !!truth;
}
/**
* @param {String} name
*/
setNickname(name) {
if (!validName(name)) return void 0;
this.nickname = name;
}
/**
* @param {Number} dex
* @return {Object}
*/
getPkmnTemplate(dex) {
let name = pokename.getPokemonNameById(dex);
return (this.owner.gameMaster.pokemon[name]);
}
upgradePkmn() {
let pkmnTmpl = this.getPkmnTemplate(this.dexNumber);
let ownerCandies = this.owner.bag.getCandyByDexNumber(this.dexNumber);
if (ownerCandies >= pkmnTmpl.CandyToEvolve) {
this.owner.bag.setCandyByDex(ownerCandies - pkmnTmpl.CandyToEvolve);
this.evolveTo(pkmnTmpl.Evolution);
}
}
/**
* @param {Number} dex
*/
evolveTo(dex) {
console.log("EVOLVE TO: ", dex);
}
/**
* @return {Object}
*/
getPokemonData() {
return ({
pokemon_id: this.dexNumber,
cp: this.cp,
stamina: this.stamina,
stamina_max: this.stamina_max,
move_1: this.move_1,
move_2: this.move_2,
height_m: this.height,
weight_kg: this.weight,
individual_attack: this.ivAttack,
individual_defense: this.ivDefense,
individual_stamina: this.ivStamina,
cp_multiplier: this.cpMultiplier
});
}
}

View File

@@ -0,0 +1,17 @@
/**
* @class MapObject
*/
export default class MapObject {
/** @constructor */
constructor() {
this.uid = 0;
this.altitude = 0;
this.latitude = 0;
this.longitude = 0;
}
}

124
src/models/World/index.js Normal file
View File

@@ -0,0 +1,124 @@
import Player from "../Player";
import CFG from "../../../cfg";
/**
* @class World
*/
export default class World {
/** @constructor */
constructor() {
this.players = [];
}
/**
* @return {Boolean}
*/
isFull() {
return (
this.players.length >= CFG.MAX_CONNECTIONS
);
}
/**
* @param {Request} req
* @param {Response} res
*/
getPlayerByRequest(req, res) {
let player = null;
return new Promise((resolve) => {
if (this.playerAlreadyConnected(req)) {
player = this.getPlayerByIP(req.headers.host);
resolve(player);
}
else {
this.addPlayer(req, res);
resolve(player);
}
});
}
/**
* @param {Object} client
* @return {Boolean}
*/
playerAlreadyConnected(client) {
let players = this.players;
let ii = 0;
let length = players.length;
let remoteAddress = client.headers.host;
for (; ii < length; ++ii) {
if (players[ii].remoteAddress === remoteAddress) {
return (true);
}
};
return (false);
}
/**
* @param {String} ip
*/
getPlayerByIP(ip) {
let players = this.players;
let ii = 0;
let length = players.length;
for (; ii < length; ++ii) {
if (players[ii].remoteAddress === ip) {
return (players[ii]);
}
};
return (null);
}
/**
* @param {Request} req
* @param {Response} res
*/
addPlayer(req, res) {
let player = new Player({
request: req,
response: res
});
this.players.push(player);
}
/**
* @param {Player} player
*/
removePlayer(player) {
console.log(player);
}
spawnFort() {
}
spawnGym() {
}
spawnEncounter() {
}
}

View File

@@ -1,14 +0,0 @@
/**
* @class GameServer
*/
class PacketModel {
/**
* @param {Player} player
* @constructor
*/
constructor(player) {
this.player = player;
}
}

View File

@@ -1,9 +0,0 @@
{
"exp": 0,
"level": 5,
"stardust": 1000,
"pokecoins": 0,
"team": 0,
"items": [],
"pokemons": []
}

View File

@@ -1,28 +0,0 @@
{
"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,18 +0,0 @@
import proto from "../proto";
/**
* @param {Object}
* @return {Object}
*/
export default function DownloadUrlEntry(obj) {
return (
new proto.Data.DownloadUrlEntry({
url: obj.url,
asset_id: obj.id,
size: obj.size,
checksum: obj.checksum
})
);
}

View File

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

View File

@@ -1,22 +0,0 @@
import proto from "../proto";
/**
* @param {Object} obj
* @return {Object}
*/
export default function ResponseEnvelope(obj) {
return (
new proto.Networking.Envelopes.ResponseEnvelope({
status_code: 53,
request_id: obj.id,
api_url: "pgorelease.nianticlabs.com/custom",
auth_ticket: new proto.Networking.Envelopes.AuthTicket({
start: new Buffer(""),
expire_timestamp_ms: 9999999999999,
end: new Buffer("")
})
}).encode().toBuffer()
);
}

View File

@@ -1,23 +0,0 @@
import proto from "../proto";
/**
* @param {Object} obj
* @return {Object}
*/
export default function ResponseEnvelope(obj) {
return (
new proto.Networking.Envelopes.ResponseEnvelope({
status_code: obj.status,
unknown6: new proto.Networking.Envelopes.Unknown6Response({
response_type: 6,
unknown2: new proto.Networking.Envelopes.Unknown6Response.Unknown2({
unknown1: 1
})
}),
request_id: obj.id,
returns: obj.response
}).encode().toBuffer()
);
}

View File

@@ -1,52 +0,0 @@
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

@@ -1,21 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
*/
export default function CheckAwardedBadges(obj) {
let buffer = {
"success": true,
"awarded_badges": [],
"awarded_badge_levels": [],
"$unknownFields": []
}
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.CheckAwardedBadgesResponse");
}

View File

@@ -1,17 +0,0 @@
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

@@ -1,25 +0,0 @@
import proto from "../proto";
import { GetPlayer } from "./";
/**
* @param {Request} req
* @param {Player} player
* @return {Object}
*/
export default function ClaimCodeName(req, player) {
let data = proto.Networking.Requests.Messages.ClaimCodenameMessage.decode(req.request_message.toBuffer());
player.username = data.codename;
return (
new proto.Networking.Responses.ClaimCodenameResponse({
codename: data.codename,
user_message: data.codename,
is_assignable: true,
status: 1
}).encode()
);
}

View File

@@ -1,19 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
*/
export default function DownloadRemoteConfigVersion(obj) {
let buffer = {
"result": "SUCCESS",
"item_templates_timestamp_ms": "1471650700946",
"asset_digest_timestamp_ms": "1467338276561000",
"$unknownFields": []
}
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.DownloadRemoteConfigVersionResponse");
}

View File

@@ -1,44 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../../cfg";
/**
* @return {Buffer}
*/
export default function DownloadSettings() {
let buffer = ({
hash: "2788184af4004004d6ab0740f7632983332106f6",
settings: {
fort_settings: {
"interaction_range_meters": 40.25098039215686,
"max_total_deployed_pokemon": 10,
"max_player_deployed_pokemon": 1,
"deploy_stamina_multiplier": 8.062745098039215,
"deploy_attack_multiplier": 0,
"far_interaction_range_meters": 1000.0156862745098
},
map_settings: {
"pokemon_visible_range": 70.00196078431372,
"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": 11.01568603515625,
"get_map_objects_min_distance_meters": 10.007843017578125,
"google_maps_api_key": CFG.GMAPS_KEY
},
inventory_settings: {
"max_pokemon": 1000,
"max_bag_items": 1000,
"base_pokemon": 250,
"base_bag_items": 350,
"base_eggs": 9
},
minimum_client_version: CFG.MINIMUM_CLIENT_VERSION
}
})
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.DownloadSettingsResponse");
}

View File

@@ -1,46 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import { decodeLong } from "../utils";
/**
* @param {Request} req
* @return {Object}
*/
export default function Encounter(encounter, req) {
let buffer = ({
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: 860075
},
status: 'ENCOUNTER_SUCCESS',
capture_probability: {
pokeball_type: ['ITEM_POKE_BALL', 'ITEM_GREAT_BALL', 'ITEM_ULTRA_BALL'],
capture_probability: [1, 1, 1]
}
});
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.EncounterResponse");
}

View File

@@ -1,22 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
/**
* @param {Request} req
* @return {Object}
*/
export default function EvolvePokemon(req) {
let data = proto.Networking.Requests.Messages.EvolvePokemonMessage.decode(req.request_message.toBuffer());
return (
new proto.Networking.Responses.EvolvePokemonResponse({
result: proto.Networking.Responses.EvolvePokemonResponse.Result.FAILED_POKEMON_CANNOT_EVOLVE,
evolved_pokemon_data: null,
experience_awarded: 0,
candy_awarded: 0
}).encode()
);
}

View File

@@ -1,27 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Request} req
* @return {Object}
*/
export default function FortDetails(req) {
let buffer = ({
"fort_id": req.fort_id,
"name": `POGOserver v${CFG.VERSION}`,
"image_urls": [
"http://thecatapi.com/api/images/get?format=src&type=png"
],
"type": "CHECKPOINT",
"latitude": req.latitude,
"longitude": req.longitude,
"modifiers": [],
"$unknownFields": []
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.FortDetailsResponse"));
}

View File

@@ -1,42 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Player} player
* @return {Buffer}
*/
export default function FortSearch(player) {
let ii = 0;
let items = [];
let name = "ultra_ball";
let amount = 5;
let exp = 50;
while (++ii < amount) {
items.push({
"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": exp,
"cooldown_complete_timestamp_ms": "1471780158665",
"chain_hack_sequence_number": 2,
"$unknownFields": []
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.FortSearchResponse"));
}

View File

@@ -1,12 +0,0 @@
import fs from "fs";
import proto from "../proto";
import CFG from "../../cfg";
/**
* @param {Player} player
* @return {Object}
*/
export default function GetAssetDigest(player) {
return (player.asset_digest.buffer);
}

View File

@@ -1,42 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../../cfg";
import {
getDownloadUrlByAssetId
} from "../utils.js";
/**
* @return {Object}
*/
export default function GetDownloadUrls(asset, ip, req) {
let key = req.asset_id[0];
let download_urls = [];
let node = null;
for (node of asset.digest) {
if (node.asset_id === key) {
break;
}
};
return new Promise((resolve) => {
download_urls.push(
{
asset_id: key,
url: `http://${ip}:${CFG.PORT}/model/${node.bundle_name}`,
size: node.size,
checksum: node.checksum
}
);
let buffer = ({
download_urls: download_urls
});
resolve(POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetDownloadUrlsResponse"));
});
}

View File

@@ -1,21 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
*/
export default function GetHatchedEggs(obj) {
let buffer = {
"success": true,
"pokemon_id": [],
"experience_awarded": [],
"candy_awarded": [],
"stardust_awarded": [],
"$unknownFields": []
};
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetHatchedEggsResponse");
}

View File

@@ -1,112 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
let isFirst = false;
/**
* @param {Object} data
* @return {Object}
*/
export default function GetInventoryData(player) {
let entries = [];
entries.push({
"modified_timestamp_ms": new Date().getTime() - 1e3,
"inventory_item_data": {
"player_stats": {
"level": player.level,
"experience": player.exp,
"prev_level_xp": "21000",
"next_level_xp": "36000",
"km_walked": 3.921541213989258,
"pokemons_encountered": 75,
"unique_pokedex_entries": 25,
"pokemons_captured": 71,
"poke_stop_visits": 123,
"pokeballs_thrown": 74,
"eggs_hatched": 1,
"big_magikarp_caught": 1,
"pokemon_deployed": 1,
"pokemon_caught_by_type": {
"type": "Buffer",
"data": [
0,
24,
0,
26,
20,
1,
0,
14,
0,
0,
1,
14,
3,
0,
1,
0,
0,
0,
3
]
}
}
}
});
for (let key in player.items) {
let amount = parseInt(player.items[key]);
if (amount > 0) {
entries.push({
"modified_timestamp_ms": new Date().getTime() - 1e3,
"inventory_item_data": {
"item": {
"item_id": "ITEM_" + key.toUpperCase(),
"count": amount
}
}
});
}
};
let party = player.party;
for (let pkmn of party) {
entries.push({
"inventory_item_data": {
"pokemon_data": {
"id": pkmn.id,
"pokemon_id": pkmn.pokemon_id,
"cp": pkmn.cp,
"stamina": pkmn.stamina,
"stamina_max": pkmn.stamina_max,
"move_1": pkmn.move_1,
"move_2": pkmn.move_2,
"height_m": pkmn.height_m,
"weight_kg": pkmn.weight_kg,
"individual_attack": pkmn.individual_attack,
"individual_defense": pkmn.individual_defense,
"individual_stamina": pkmn.individual_stamina,
"cp_multiplier": pkmn.cp_multiplier,
"pokeball": pkmn.pokeball,
"captured_cell_id": pkmn.captured_cell_id,
"creation_time_ms": pkmn.creation_time_ms,
"favorite": pkmn.favorite
}
}
});
};
let buffer = ({
"success": true,
"inventory_delta": {
"new_timestamp_ms": new Date().getTime() - 1e3,
"inventory_items": entries
}
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetInventoryResponse"));
}

View File

@@ -1,195 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Player} player
* @param {Request} request
* @return {Object}
*/
export default function GetMapObjects(player, wild_pkmns, request) {
let cells = request.cell_id;
let cellsRes = [];
let pokemon_id = 121;
cells.forEach((cell) => {
cellsRes.push({
s2_cell_id: cell,
current_timestamp_ms: new Date().getTime() * 1e3,
forts: [],
spawn_points: [],
deleted_objects: [],
is_truncated_list: false,
fort_summaries: [],
decimated_spawn_points: [],
wild_pokemons: [],
catchable_pokemons: [],
nearby_pokemons: []
});
});
let latitude = player.latitude;
let longitude = player.longitude;
let cell = cellsRes[0];
cell.forts = [
{
"id": "108dc9c703a94b619a53a3c29b5c676f.11",
"last_modified_timestamp_ms": "1471621873766",
"latitude": latitude + 0.0002,
"longitude": longitude - 0.0001,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "1391315b489f421abd52ce10b6da7dd3.16",
"last_modified_timestamp_ms": "1471776325164",
"latitude": 39.188351,
"longitude": -96.582561,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "33ad17c71fff4797b7f25dcfcdca48df.16",
"last_modified_timestamp_ms": "1470755536809",
"latitude": 39.189386,
"longitude": -96.581113,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "40f86138ca6f49cc9e98e18b77d6067a.16",
"last_modified_timestamp_ms": "1471748353301",
"latitude": 39.188351,
"longitude": -96.582209,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "560ef7ed6cb5469db29b543cce7677ae.16",
"last_modified_timestamp_ms": "1469923654520",
"latitude": 39.186848,
"longitude": -96.581267,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "60d2ffcfe9cf4003b4d94bcc9ee0c318.16",
"last_modified_timestamp_ms": "1471811998365",
"latitude": 39.188008,
"longitude": -96.582409,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "637941f1f2494276884ede4fc538c2b2.16",
"last_modified_timestamp_ms": "1471816829142",
"latitude": 39.186868,
"longitude": -96.583295,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "7c0154d02e4f4d91b9b74214eda75abc.16",
"last_modified_timestamp_ms": "1471483788730",
"latitude": 39.187991,
"longitude": -96.581251,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "8a94bf6cd17b43be8b5b42655d23e2f6.16",
"last_modified_timestamp_ms": "1471751252546",
"latitude": 39.187684,
"longitude": -96.583537,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "9b469dbd550f43b5a8e94f941d66bc43.16",
"last_modified_timestamp_ms": "1471243641146",
"latitude": 39.189051,
"longitude": -96.581804,
"enabled": true,
"type": "CHECKPOINT"
},
{
"id": "bb0e515e3f554b398f1fa9c58435dc78.16",
"last_modified_timestamp_ms": "1471748285036",
"latitude": 39.188823,
"longitude": -96.582742,
"enabled": true,
"type": "CHECKPOINT"
}
];
cell.spawn_points = [
{
"latitude": 39.188870250798956,
"longitude": -96.58196728549451
},
{
"latitude": 39.1889464335866,
"longitude": -96.58205070456887
},
{
"latitude": 39.18887496474473,
"longitude": -96.58188386652927
},
{
"latitude": 39.18879406783625,
"longitude": -96.58188386652927
},
{
"latitude": 39.189284161630674,
"longitude": -96.58180044767312
}
];
for (let pkmn of wild_pkmns) {
cell.wild_pokemons.push({
encounter_id: pkmn.encounter_id,
last_modified_timestamp_ms: new Date().getTime(),
latitude: pkmn.latitude,
longitude: pkmn.longitude,
spawn_point_id: "87bdd289c69",
pokemon_data: {
pokemon_id: pkmn.pokemon_id,
cp: pkmn.cp,
stamina: 41,
stamina_max: 41,
move_1: 221,
move_2: 26,
height_m: 0.22802678267819977,
weight_kg: 1.3452539511871338,
individual_attack: 9,
individual_defense: 13,
individual_stamina: 14,
cp_multiplier: 0.5663545199394226
},
time_till_hidden_ms: 730176
});
cell.catchable_pokemons.push({
spawn_point_id: "87bdd289c69",
encounter_id: pkmn.encounter_id,
pokemon_id: pkmn.pokemon_id,
latitude: latitude,
longitude: longitude,
expiration_timestamp_ms: (new Date().getTime() + 1e6) * 1e3
});
cell.nearby_pokemons.push({
distance_in_meters: 200.0,
pokemon_id: pkmn.pokemon_id
});
};
let buffer = ({
status: "SUCCESS",
map_cells: cellsRes
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetMapObjectsResponse"));
}

View File

@@ -1,101 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
*/
function getPlayerDataPacket(obj) {
return (
{
creation_timestamp_ms: 1467936859925,
username: obj.username,
team: proto.Enums.TeamColor.YELLOW,
tutorial_state: obj.tutorial_state,
avatar: obj.avatar,
max_pokemon_storage: 250,
max_item_storage: 350,
daily_bonus: {
next_defender_bonus_collect_timestamp_ms: 1470174535972
},
contact_settings: obj.contact_settings,
currencies: obj.currencies
}
);
}
/**
* @param {Object} obj
* @return {Object}
*/
function buildPlayerData(obj) {
let team = obj.team;
let username = obj.username;
let pokecoins = obj.pokecoins;
let stardust = obj.stardust;
let avatar = {
skin: obj.skin,
hair: obj.hair,
shirt: obj.shirt,
pants: obj.pants,
hat: obj.hat,
shoes: obj.shoes,
eyes: obj.eyes,
gender: obj.gender,
backpack: obj.backpack
};
let contact_settings = {
send_marketing_emails: obj.send_marketing_emails,
send_push_notifications: obj.send_push_notifications
};
let tutorial_state = [
proto.Enums.TutorialState.LEGAL_SCREEN,
proto.Enums.TutorialState.AVATAR_SELECTION,
proto.Enums.TutorialState.POKEMON_CAPTURE,
proto.Enums.TutorialState.NAME_SELECTION,
proto.Enums.TutorialState.FIRST_TIME_EXPERIENCE_COMPLETE
];
let currencies = [
{
name: "POKECOIN",
amount: pokecoins
},
{
name: "STARDUST",
amount: stardust
}
];
return ({
username: username,
team: team,
tutorial_state: tutorial_state,
contact_settings: contact_settings,
avatar: avatar,
currencies: currencies
});
}
export default function GetPlayer(obj) {
let data = buildPlayerData(obj);
let packet = getPlayerDataPacket(data);
let buffer = {
success: true,
player_data: packet
};
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerResponse"));
}

View File

@@ -1,168 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} obj
* @return {Object}
*/
export default function GetPlayerProfile(obj) {
let buffer = ({
"result": "SUCCESS",
"start_time": "1471096437979",
"badges": [
{
"badge_type": "BADGE_TRAVEL_KM",
"end_value": 10,
"current_value": 3.921541213989258
},
{
"badge_type": "BADGE_POKEDEX_ENTRIES",
"rank": 1,
"start_value": 5,
"end_value": 50,
"current_value": 25
},
{
"badge_type": "BADGE_CAPTURE_TOTAL",
"rank": 1,
"start_value": 30,
"end_value": 500,
"current_value": 71
},
{
"badge_type": "BADGE_EVOLVED_TOTAL",
"end_value": 3
},
{
"badge_type": "BADGE_HATCHED_TOTAL",
"end_value": 10,
"current_value": 1
},
{
"badge_type": "BADGE_POKESTOPS_VISITED",
"rank": 1,
"start_value": 100,
"end_value": 1000,
"current_value": 123
},
{
"badge_type": "BADGE_BIG_MAGIKARP",
"end_value": 3,
"current_value": 1
},
{
"badge_type": "BADGE_BATTLE_ATTACK_WON",
"end_value": 10
},
{
"badge_type": "BADGE_BATTLE_TRAINING_WON",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_NORMAL",
"rank": 1,
"start_value": 10,
"end_value": 50,
"current_value": 24
},
{
"badge_type": "BADGE_TYPE_FIGHTING",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_FLYING",
"rank": 1,
"start_value": 10,
"end_value": 50,
"current_value": 26
},
{
"badge_type": "BADGE_TYPE_POISON",
"rank": 1,
"start_value": 10,
"end_value": 50,
"current_value": 20
},
{
"badge_type": "BADGE_TYPE_GROUND",
"end_value": 10,
"current_value": 1
},
{
"badge_type": "BADGE_TYPE_ROCK",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_BUG",
"rank": 1,
"start_value": 10,
"end_value": 50,
"current_value": 14
},
{
"badge_type": "BADGE_TYPE_GHOST",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_STEEL",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_FIRE",
"end_value": 10,
"current_value": 1
},
{
"badge_type": "BADGE_TYPE_WATER",
"rank": 1,
"start_value": 10,
"end_value": 50,
"current_value": 14
},
{
"badge_type": "BADGE_TYPE_GRASS",
"end_value": 10,
"current_value": 3
},
{
"badge_type": "BADGE_TYPE_ELECTRIC",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_PSYCHIC",
"end_value": 10,
"current_value": 1
},
{
"badge_type": "BADGE_TYPE_ICE",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_DRAGON",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_DARK",
"end_value": 10
},
{
"badge_type": "BADGE_TYPE_FAIRY",
"end_value": 10,
"current_value": 3
},
{
"badge_type": "BADGE_SMALL_RATTATA",
"end_value": 3
},
{
"badge_type": "BADGE_PIKACHU",
"end_value": 3
}
],
"$unknownFields": []
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerProfileResponse"));
}

View File

@@ -1,13 +0,0 @@
import CFG from "../../cfg";
import fs from "fs";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Buffer} master
* @return {Object}
*/
export default function ItemTemplates(master) {
return (master);
}

View File

@@ -1,21 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import { GetPlayer } from "./";
/**
* @param {Object} obj
* @return {Object}
*/
export default function LevelUpRewards(obj) {
let buffer = {
"result": "AWARDED_ALREADY",
"items_awarded": [],
"items_unlocked": [],
"$unknownFields": []
}
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.LevelUpRewardsResponse");
}

View File

@@ -1,25 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import { GetPlayer } from "./";
/**
* @param {Player} player
* @param {Object} req
* @return {Object}
*/
export default function MarkTutorialComplete(player, req) {
if (req.tutorials_completed[0] === "LEGAL_SCREEN") {
player.tutorial_state.push("LEGAL_SCREEN");
player.send_marketing_emails = !!req.send_marketing_emails;
}
let buffer = ({
success: true,
player_data: GetPlayer(player).player_data
});
return POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetHatchedEggsResponse");
}

View File

@@ -1,21 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
/**
* @param {Request} req
* @return {Object}
*/
export default function NicknamePokemon(req) {
let data = proto.Networking.Requests.Messages.NicknamePokemonMessage.decode(req.request_message.toBuffer());
// TODO: Save nickname into db
return (
new proto.Networking.Responses.NicknamePokemonResponse({
result: proto.Networking.Responses.NicknamePokemonResponse.Result.ERROR_INVALID_NICKNAME
}).encode()
);
}

View File

@@ -1,23 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import { GetPlayer } from "./";
/**
* @param {Player} player
* @return {Object}
*/
export default function SetAvatar(player) {
let buffer = ({
status: proto.Networking.Responses.SetAvatarResponse.Status.SUCCESS,
player_data: GetPlayer(player)
});
if (player.tutorial_state.indexOf("AVATAR_SELECTION") === -1) {
player.tutorial_state.push("AVATAR_SELECTION");
}
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.SetAvatarResponse"));
}

View File

@@ -1,20 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import { GetPlayer } from "./";
/**
* @param {Player} player
* @return {Object}
*/
export default function SetContactSettings(player) {
return (
new proto.Networking.Responses.SetContactSettingsResponse({
status: proto.Networking.Responses.SetContactSettingsResponse.Status.SUCCESS,
player_data: GetPlayer(player).player_data
}).encode()
);
}

View File

@@ -1,22 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Request} req
* @return {Object}
*/
export default function SetFavoritePokemon(player, req) {
let buffer = {
"result": "SUCCESS",
};
player.setFavoritePkmn(req.pokemon_id << 0, req.is_favorite);
return (
POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.SetFavoritePokemonResponse")
);
}

View File

@@ -1,650 +0,0 @@
import proto from "../proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../../cfg";
/**
* @param {Object} obj
* @return {Object}
*/
export default function SfidaActionLog(obj) {
let buffer = ({
"result": "SUCCESS",
"log_entries": [
{
"timestamp_ms": "1471694560585",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "HORSEA",
"combat_points": 110
}
},
{
"timestamp_ms": "1471694566830",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "HORSEA",
"combat_points": 73
}
},
{
"timestamp_ms": "1471694573468",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471694597662",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "HORSEA",
"combat_points": 102
}
},
{
"timestamp_ms": "1471694603880",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "CATERPIE",
"combat_points": 36
}
},
{
"timestamp_ms": "1471694610259",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "WEEDLE",
"combat_points": 15
}
},
{
"timestamp_ms": "1471694616586",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "PIDGEY",
"combat_points": 26
}
},
{
"timestamp_ms": "1471694632969",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 1
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471694739319",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471694741772",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 4
}
]
}
},
{
"timestamp_ms": "1471694904167",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "KRABBY",
"combat_points": 100
}
},
{
"timestamp_ms": "1471694925722",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 2
},
{
"item_id": "ITEM_POKE_BALL",
"count": 4
}
]
}
},
{
"timestamp_ms": "1471695030964",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471695071016",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695089887",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "SPEAROW",
"combat_points": 80
}
},
{
"timestamp_ms": "1471695096341",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471695139926",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "EKANS",
"combat_points": 72
}
},
{
"timestamp_ms": "1471695148440",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695195481",
"catch_pokemon": {
"result": "UNKNOWN_ENUM_VALUE_Result_3",
"pokemon_id": "MAGIKARP",
"combat_points": 26
}
},
{
"timestamp_ms": "1471695197676",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "ZUBAT",
"combat_points": 41
}
},
{
"timestamp_ms": "1471695203917",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "MAGIKARP",
"combat_points": 46
}
},
{
"timestamp_ms": "1471695211919",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471695316895",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "ZUBAT",
"combat_points": 43
}
},
{
"timestamp_ms": "1471695323589",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471695429795",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 1
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695487237",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471695522740",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471695577816",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 1
},
{
"item_id": "ITEM_POTION",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471695633092",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 1
},
{
"item_id": "ITEM_POTION",
"count": 2
}
],
"eggs": 1
}
},
{
"timestamp_ms": "1471695738726",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471695776746",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_REVIVE",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695790415",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_REVIVE",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 4
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695829422",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "MAGIKARP",
"combat_points": 40
}
},
{
"timestamp_ms": "1471695836445",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695838748",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695860629",
"catch_pokemon": {
"result": "POKEMON_FLED",
"pokemon_id": "VENONAT",
"combat_points": 174
}
},
{
"timestamp_ms": "1471695866223",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471695884419",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "STARYU",
"combat_points": 11
}
},
{
"timestamp_ms": "1471695889856",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471695906137",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "PINSIR",
"combat_points": 28
}
},
{
"timestamp_ms": "1471695914356",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471696008778",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471696010713",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "CATERPIE",
"combat_points": 74
}
},
{
"timestamp_ms": "1471696050313",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471696052566",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
},
{
"timestamp_ms": "1471696072147",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 1
},
{
"item_id": "ITEM_POTION",
"count": 2
}
]
}
},
{
"timestamp_ms": "1471696074058",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "ZUBAT",
"combat_points": 40
}
},
{
"timestamp_ms": "1471696079308",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_RAZZ_BERRY",
"count": 1
},
{
"item_id": "ITEM_POKE_BALL",
"count": 2
},
{
"item_id": "ITEM_POTION",
"count": 1
}
]
}
},
{
"timestamp_ms": "1471696081215",
"catch_pokemon": {
"result": "POKEMON_CAPTURED",
"pokemon_id": "ZUBAT",
"combat_points": 73
}
},
{
"timestamp_ms": "1471696235352",
"fort_search": {
"result": "SUCCESS",
"items": [
{
"item_id": "ITEM_POKE_BALL",
"count": 3
}
]
}
}
],
"$unknownFields": []
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.SfidaActionLogResponse"));
}

View File

@@ -1,71 +0,0 @@
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

@@ -1,20 +0,0 @@
import CFG from "../../cfg";
import proto from "../proto";
/**
* @param {Request} req
* @return {Object}
*/
export default function UpgradePokemon(req) {
let data = proto.Networking.Requests.Messages.UpgradePokemonMessage.decode(req.request_message.toBuffer());
return (
new proto.Networking.Responses.UpgradePokemonResponse({
result: proto.Networking.Responses.UpgradePokemonResponse.Result.ERROR_UPGRADE_NOT_AVAILABLE,
upgraded_pokemon: null
}).encode()
);
}

View File

@@ -1,42 +0,0 @@
export DownloadRemoteConfigVersion from "./Responses.DownloadRemoteConfigVersion";
export DownloadSettings from "./Responses.DownloadSettings";
export GetAssetDigest from "./Responses.GetAssetDigest";
export GetHatchedEggs from "./Responses.GetHatchedEggs";
export GetInventory from "./Responses.GetInventory";
export GetPlayer from "./Responses.GetPlayer";
export GetPlayerProfile from "./Responses.GetPlayerProfile";
export FortDetails from "./Responses.FortDetails";
export FortSearch from "./Responses.FortSearch";
export GetMapObjects from "./Responses.GetMapObjects";
export SetContactSettings from "./Responses.SetContactSettings";
export ItemTemplates from "./Responses.ItemTemplates";
export CheckAwardedBadges from "./Responses.CheckAwardedBadges";
export GetDownloadUrls from "./Responses.GetDownloadUrls";
export MarkTutorialComplete from "./Responses.MarkTutorialComplete";
export ClaimCodeName from "./Responses.ClaimCodeName";
export LevelUpRewards from "./Responses.LevelUpRewards";
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

@@ -1,556 +0,0 @@
import proto from "./proto";
import CFG from "../cfg";
import {
getHashCodeFrom,
decodeRequestEnvelope
} from "./utils";
import {
ResponseEnvelope,
ResponseEnvelopeAuth
} from "./packets";
import jwtDecode from "jwt-decode";
import { GetPlayer } from "./packets";
/**
* @class Player
*/
class Player {
/** @constructor */
constructor(obj) {
this.uid = -1;
this.owner_id = -1;
this._email = null;
this.username = "unknown";
this.latitude = 0;
this.longitude = 0;
this.altitude = 0;
this.send_marketing_emails = false;
this.send_push_notifications = false;
this.exp = 0;
this.level = 1;
this.stardust = 0;
this.pokecoins = 0;
this.team = 0;
this.skin = 0;
this.hair = 0;
this.shirt = 0;
this.pants = 0;
this.hat = 0;
this.shoes = 0;
this.eyes = 0;
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;
this.pokedex = null;
this.inventory = null;
this.asset_digest = null;
this.hasSignature = false;
this.isIOS = false;
this.isAndroid = false;
this.isPTCAccount = false;
this.isGoogleAccount = false;
this.request = obj.request;
this.response = null;
this.connection = obj.connection;
this.timeout = obj.timeout;
this.remotePort = obj.remotePort;
this.remoteAddress = obj.remoteAddress;
this.currentEncounter = null;
this.loggedIn = obj.loggedIn || false;
this.authenticated = false;
this.authentications = 0;
}
get email() {
return (this._email);
}
set email(value) {
this._email = value.replace("@gmail.com", "");
}
/**
* @param {String} email
*/
generateUid(email) {
this.uid = getHashCodeFrom(String(email));
}
/**
* @param {Buffer} buffer
*/
sendResponse(buffer) {
this.response.end(buffer);
}
/**
* @param {Response} res
*/
updateResponse(res) {
this.response = res;
}
updateByObject(obj) {
for (let key in obj) {
if (this.hasOwnProperty(key)) {
if (key === "send_marketing_emails" || key === "send_push_notifications") {
this[key] = !!obj[key];
}
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];
}
};
}
/**
* @param {Object} obj
*/
updatePosition(obj) {
this.latitude = obj.latitude;
this.longitude = obj.longitude;
}
updateAvatar(req) {
let node = null;
for (let key in req.player_avatar) {
node = req.player_avatar[key];
if (key === "gender") {
this.gender = node === "FEMALE" ? 1 : 0;
}
else {
if (this.hasOwnProperty(key)) {
this[key] = node;
}
}
};
}
updateContactSettings(req) {
let data = proto.Networking.Requests.Messages.SetContactSettingsMessage.decode(req.request_message.toBuffer()).contact_settings;
if (!data) return void 0;
this.send_marketing_emails = data.send_marketing_emails;
this.send_push_notifications = data.send_push_notifications;
}
getPkmnIndexFromPartyById(id) {
for (let ii = 0; ii < this.party.length; ++ii) {
if (this.party[ii].id === id) return (ii);
};
return (-1);
}
getPkmnFromPartyById(id) {
let index = this.getPkmnIndexFromPartyById(id);
return (this.party[index]);
}
deletePkmnFromParty(id) {
let index = this.getPkmnIndexFromPartyById(id);
let pkmn = this.party[index];
if (pkmn) this.party.splice(index, 1);
}
setFavoritePkmn(id, favorite) {
let pkmn = this.getPkmnFromPartyById(id);
if (pkmn) pkmn.favorite = favorite;
}
}
/**
* @param {String} name
* @return {Boolean}
*/
export function validPlayerName(name) {
return !(
name === null ||
name === void 0 ||
typeof name === "string" &&
name.length <= 1
);
}
/**
* @param {Player} player
*/
export function getPlayerIndex(player) {
let ip = player.remoteAddress;
let index = -1;
let ii = 0, length = this.clients.length;
for (; ii < length; ++ii) {
if (this.clients[ii].remoteAddress === ip) {
index = ii;
break;
}
};
return (index);
}
/**
* @param {Request} req
*/
export function getPlayerByRequest(req) {
return (
this.getPlayerByIP(req.headers.host)
);
}
/**
* @param {String} ip
*/
export function getPlayerByIP(ip) {
let ii = 0, length = this.clients.length;
for (; ii < length; ++ii) {
if (this.clients[ii].remoteAddress === ip) {
return (this.clients[ii]);
}
};
return (null);
}
/**
* @param {String} name
*/
export function getPlayerByName(name) {
let ii = 0, length = this.clients.length;
for (; ii < length; ++ii) {
if (this.clients[ii].username === name) {
return (this.clients[ii]);
}
};
return (null);
}
/**
* @param {Request} req
* @return {Player}
*/
export function addPlayer(req) {
let connection = req.connection;
let player = new Player({
timeout: this.time,
connection: connection,
request: req,
remotePort: connection.remotePort,
remoteAddress: req.headers.host
});
this.clients.push(player);
return (player);
}
/**
* @param {Player} player
*/
export function removePlayer(player) {
let index = this.getPlayerIndex(player);
if (index >= 0) {
this.clients.splice(index, 1);
this.print(`${player.remoteAddress} disconnected!`, 36);
this.emit("killPlayer", player);
}
else {
this.print("Failed at removing player", 33);
}
}
/**
* @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 (!this.validPlayerName(name)) {
this.print(`Invalid player name!`, 31);
return void 0;
}
let player = this.getPlayerByName(name);
if (player !== null) {
this.removePlayer(player);
this.print(`Kicked ${name} from the server!`);
}
else this.print(`Failed to kick ${name} from the server!`, 31);
}
export function updatePlayers() {
//this.print("Updating players");
}
export function saveAllPlayers() {
for (let client of this.clients) {
this.savePlayer(client);
};
}
export function removeAllPlayers() {
for (let client of this.clients) {
this.removePlayer(client);
};
}
/**
* @param {Player} player
*/
export function savePlayer(player) {
return new Promise((resolve) => {
if (player.authenticated) {
this.updateUser(player).then(() => {
this.updateUserItems(player).then(() => {
this.updateUserParty(player).then(() => {
// refresh player data by database
this.loginPlayer(player).then(resolve);
});
});
});
}
});
}
/**
* @param {Player} player
*/
export function forwardPlayer(player) {
return new Promise((resolve) => {
this.getUserByEmail(player.email).then((doc) => {
if (player.email.length) {
let provider = player.isGoogleAccount ? "Google" : "PTC";
this.print(`${player.email} authenticated via ${provider}!`, 36);
}
if (doc) {
this.loginPlayer(player).then((res) => {
this.emit("loginPlayer", player);
resolve(res);
});
}
else {
this.registerPlayer(player).then((res) => {
this.emit("registerPlayer", player);
resolve(res);
});
}
});
});
}
/**
* @param {Player} player
*/
export function loginPlayer(player) {
return new Promise((resolve) => {
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);
});
});
});
}
/**
* @param {Player} player
*/
export function registerPlayer(player) {
return new Promise((resolve) => {
this.createUser(player).then(() => {
this.print(`${player.email} registered!`, 36);
this.loginPlayer(player).then((res) => {
resolve(res);
});
});
});
}
/**
* @param {Player} player
* @return {Buffer}
*/
export function authenticatePlayer(player) {
let request = decodeRequestEnvelope(player.request.body);
let msg = ResponseEnvelopeAuth({
id: request.request_id
});
let token = request.auth_info;
// TODO: Support PTC server authentification
if (!token || !token.provider) {
this.print("Invalid authentication token! Kicking..", 31);
this.removePlayer(player);
return void 0;
}
if (token.provider === "google") {
if (token.token !== null) {
let decoded = jwtDecode(token.token.contents);
player.generateUid(decoded.email);
player.email = decoded.email;
player.email_verified = decoded.email_verified;
player.isGoogleAccount = true;
this.print(`${player.email} connected!`, 36);
}
else {
this.print("Invalid authentication token! Kicking..", 31);
this.removePlayer(player);
return void 0;
}
}
else if (token.provider === "ptc") {
let decoded = token.token.contents;
player.isPTCAccount = true;
player.email = decoded.split("-")[1];
player.email_verified = true;
player.isPTCAccount = true;
//console.log(decoded);
this.print("PTC auth isnt supported yet! Your progress wont get saved!", 33);
//this.removePlayer(player);
//return void 0;
}
else {
this.print("Invalid provider! Kicking..", 31);
this.removePlayer(player);
return void 0;
}
player.authenticated = true;
return (msg);
}

View File

@@ -5,10 +5,11 @@ import CFG from "../cfg";
const helpMessage = fs.readFileSync(".help", "utf8");
export function processCommand(cmd, data) {
let players = this.world.players;
switch (cmd) {
// How many active connections there are
case "/clients":
var length = this.clients.length;
case "/players":
var length = players.length;
this.print(`${length}:${CFG.MAX_CONNECTIONS} connected players!`, 33);
break;
// Exit the server
@@ -19,9 +20,9 @@ export function processCommand(cmd, data) {
this.kickPlayer(data[1]);
break;
case "/killall":
var length = this.clients.length;
var length = players.length;
this.removeAllPlayers();
var result = length - this.clients.length;
var result = length - players.length;
this.print(`Removed ${result} player${result === 1 ? "": "s"}!`);
break;
case "/clear":
@@ -35,7 +36,7 @@ export function processCommand(cmd, data) {
break;
case "/save":
this.saveAllPlayers();
var length = this.clients.length;
var length = players.length;
this.print(`Saved ${length} player${length === 1 ? "": "s"} into database!`);
break;
case "/spawn":

View File

@@ -1,3 +0,0 @@
import pogo from "node-pogo-protos";
export default pogo;

View File

@@ -1,24 +1,16 @@
import fs from "fs";
import url from "url";
import proto from "./proto";
import pcrypt from "pcrypt";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
import {
ResponseEnvelope,
AuthTicket,
ShopData
} from "./packets";
/**
* @param {Player} player
* @param {Request} req
* @param {Response} res
*/
export function routeRequest(req, res) {
let player = this.getPlayerByRequest(req);
export function routeRequest(player, req, res) {
let parsed = url.parse(req.url).pathname;
let route = parsed.split("/");
@@ -27,11 +19,11 @@ export function routeRequest(req, res) {
switch (route[1]) {
case "plfe":
case "custom":
if (route[2] === "rpc") this.onRequest(req);
if (route[2] === "rpc") this.onRequest(player, req);
break;
case "model":
// make sure no random dudes can access download
if (!player.authenticated || !player.email_verified) return void 0;
if (!player.authenticated) return void 0;
let name = route[2];
if (name && name.length > 1) {
let folder = player.isAndroid ? "android/" : "ios/";
@@ -45,14 +37,6 @@ export function routeRequest(req, res) {
});
}
break;
case "om":
if (
route[2] === "glm" &&
route[3] === "mmap"
) {
this.print(`Received gmaps request!`, 33);
}
break;
default:
console.log(`Unknown request url: https://${req.headers.host}${req.url}`);
break;
@@ -60,43 +44,14 @@ export function routeRequest(req, res) {
}
export function parseProtobuf(buffer, path) {
try {
return POGOProtos.parseWithUnknown(buffer, path);
} catch (e) {
this.print(e, 31);
}
}
/**
* @param {Player} player
* @param {Request} req
*/
export function parseSignature(req) {
let key = pcrypt.decrypt(req.unknown6.unknown2.encrypted_signature);
return (
POGOProtos.parseWithUnknown(key, "POGOProtos.Networking.Envelopes.Signature")
);
}
/**
* @param {Request} req
*/
export function onRequest(req) {
let player = this.getPlayerByRequest(req);
// Validate email verification
if (player.authenticated) {
if (!player.email_verified) {
this.print(`${player.email}'s email isnt verified, kicking..`, 31);
this.removePlayer(player);
return void 0;
}
}
export function onRequest(player, req) {
let request = this.parseProtobuf(req.body, "POGOProtos.Networking.Envelopes.RequestEnvelope");
request.requests = request.requests || [];
request.requests = request.requests || [];
if (CFG.DEBUG_LOG_REQUESTS) {
console.log("#####");
@@ -111,23 +66,15 @@ export function onRequest(req) {
}
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.print("Received invalid request!", 31);
return void 0;
}
this.processRequests(player, request.requests).then((returns) => {
if (CFG.DEBUG_DUMP_TRAFFIC) {
this.dumpTraffic(request, returns);
}
let msg = this.envelopResponse(1, returns, request, player, !!request.auth_ticket, false);
let msg = this.envelopResponse(1, returns, request, player, !!request.auth_ticket);
player.sendResponse(msg);
});
@@ -139,10 +86,9 @@ export function onRequest(req) {
* @param {Request} req
* @param {Player} player
* @param {Boolean} auth
* @param {Boolean} shop
* @return {Buffer}
*/
export function envelopResponse(status, returns, req, player, auth, shop) {
export function envelopResponse(status, returns, req, player, auth) {
let buffer = req;
@@ -163,9 +109,8 @@ export function envelopResponse(status, returns, req, player, auth, shop) {
}
if (auth) buffer.auth_ticket = AuthTicket();
if (shop) buffer.unknown6 = [ShopData()];
if (buffer.unknown6 && !shop) {
if (buffer.unknown6) {
buffer.unknown6 = [{
"response_type": 6,
"unknown2": {
@@ -197,7 +142,7 @@ export function processRequests(player, requests) {
let length = requests.length;
let body = [];
let loop = (index) => {
const loop = (index) => {
this.processResponse(player, requests[index]).then((request) => {
body.push(request);
if (++index >= length) resolve(body);
@@ -209,12 +154,4 @@ export function processRequests(player, requests) {
});
}
/**
* @param {Request} req
* @return {Boolean}
*/
export function validRequest(req) {
return (true);
}

View File

@@ -1,40 +1,27 @@
import proto from "./proto";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
import {
GetInventory,
GetHatchedEggs,
CheckAwardedBadges,
DownloadSettings,
DownloadRemoteConfigVersion,
GetPlayerProfile,
ItemTemplates,
GetPlayer,
GetAssetDigest,
GetDownloadUrls,
GetMapObjects,
SfidaActionLog,
FortDetails,
FortSearch,
SetContactSettings,
SetAvatar,
MarkTutorialComplete,
LevelUpRewards,
Encounter,
CatchPokemon,
NicknamePokemon,
UpgradePokemon,
EvolvePokemon,
SetFavoritePokemon,
ClaimCodeName,
CheckChallenge
} from "./packets";
_toCC,
validUsername
} from "./utils";
import { _toCC } from "./utils";
const REQUEST = proto.Networking.Requests.RequestType;
/**
* @param {Request} req
* @return {Buffer}
*/
export function parseMessage(req) {
let proto = `POGOProtos.Networking.Requests.Messages.${cc}Message`;
if (req.request_message) {
try {
return (this.parseProtobuf(req.request_message, proto));
} catch (e) {
this.print(`Failed to parse ${cc}: ${e}`, 31);
}
}
return void 0;
}
/**
* @param {Player} player
@@ -46,196 +33,12 @@ export function processResponse(player, req) {
let buffer = null;
let cc = _toCC(req.request_type);
let msg = null;
let proto = `POGOProtos.Networking.Requests.Messages.${cc}Message`;
if (req.request_message) {
try {
msg = this.parseProtobuf(req.request_message, proto);
} catch (e) {
this.print(`Failed to parse ${cc}: ${e}`, 31);
}
}
let msg = this.parseMessage(req);
return new Promise((resolve) => {
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(player);
break;
case "CHECK_AWARDED_BADGES":
buffer = CheckAwardedBadges();
break;
case "DOWNLOAD_SETTINGS":
buffer = DownloadSettings();
break;
case "DOWNLOAD_ITEM_TEMPLATES":
buffer = ItemTemplates(this.master);
break;
case "DOWNLOAD_REMOTE_CONFIG_VERSION":
buffer = DownloadRemoteConfigVersion(msg);
break;
case "GET_ASSET_DIGEST":
buffer = GetAssetDigest(player);
break;
case "GET_PLAYER_PROFILE":
buffer = GetPlayerProfile();
break;
case "GET_MAP_OBJECTS":
player.updatePosition(msg);
buffer = GetMapObjects(player, this.wild_pokemons, msg);
this.savePlayer(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "GET_DOWNLOAD_URLS":
GetDownloadUrls(player.asset_digest.decode, CFG.LOCAL_IP || this.getLocalIPv4(), msg).then((res) => {
resolve(res);
});
return void 0;
break;
case "SET_AVATAR":
player.updateAvatar(msg);
this.emit("updatePlayerAvatar", player);
buffer = SetAvatar(player);
this.savePlayer(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "SFIDA_ACTION_LOG":
buffer = SfidaActionLog();
break;
case "MARK_TUTORIAL_COMPLETE":
buffer = MarkTutorialComplete(player, msg);
this.savePlayer(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "ENCOUNTER_TUTORIAL_COMPLETE":
let starters = ["BULBASAUR", "CHARMANDER", "SQUIRTLE"];
// Make sure the catched pokemon is valid
if (starters.indexOf(msg.pokemon_id) === -1) {
if (player.tutorial_state.indexOf("POKEMON_CAPTURE") === -1) {
player.tutorial_state.push("POKEMON_CAPTURE");
}
let pkmn = {
pokemon_id: msg.pokemon_id,
cp: 15,
stamina: 10,
stamina_max: 10,
move_1: "TACKLE",
move_2: "TACKLE",
height_m: 0.20962005257606506,
weight_kg: 0.3212273120880127,
individual_attack: 7,
individual_defense: 7,
individual_stamina: 3,
cp_multiplier: 0.16639786958694458
};
player.party.push(pkmn);
buffer = POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.EncounterTutorialCompleteResponse");
}
break;
case "CLAIM_CODENAME":
buffer = ClaimCodeName(msg, player);
this.savePlayer(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "LEVEL_UP_REWARDS":
buffer = LevelUpRewards();
break;
case "FORT_DETAILS":
buffer = FortDetails(msg);
break;
case "FORT_SEARCH":
buffer = FortSearch(player);
this.updateUserItems(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "SET_CONTACT_SETTINGS":
player.updateContactSettings(msg);
buffer = SetContactSettings(player);
this.savePlayer(player).then(() => {
resolve(buffer);
});
return void 0;
break;
case "ENCOUNTER":
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);
break;
case "UPGRADE_POKEMON":
buffer = UpgradePokemon(msg);
break;
case "EVOLVE_POKEMON":
buffer = EvolvePokemon(msg);
break;
case "SET_FAVORITE_POKEMON":
buffer = SetFavoritePokemon(player, msg);
break;
case "RELEASE_POKEMON":
buffer = {
result: "SUCCESS",
candy_awarded: 5
};
let id = msg.pokemon_id << 0;
this.deleteOwnedPokemon(id).then(() => {
player.deletePkmnFromParty(id);
buffer = POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.ReleasePokemonResponse");
resolve(buffer);
});
return void 0;
break;
default:
this.print(`Unknown request: ${req.request_type}`, 31);
break;
@@ -248,25 +51,4 @@ 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

@@ -1,11 +1,14 @@
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";
import * as master from "./master";
import GameMaster from "./models/GameMaster";
import {
capitalize,
idToPkmnBundleName
@@ -13,7 +16,7 @@ import {
export function setup() {
let isFirstRun = !this.directoryExists(CFG.DUMP_ASSET_PATH);
let isFirstRun = !this.fileExists(CFG.DUMP_ASSET_PATH);
if (isFirstRun) {
this.print("Required assets are missing! Preparing dump session..", 31);
@@ -30,7 +33,9 @@ export function setup() {
this.print(`Downloaded assets are valid! Proceeding..`);
this.master = POGOProtos.serialize(this.parseGameMaster(), "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
master.GAME_MASTER = this.parseGameMaster();
this.master = POGOProtos.serialize(fs.readFileSync(CFG.DUMP_ASSET_PATH + "game_master"), "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
this.setupDatabaseConnection().then(() => {
if (CFG.PORT < 1) {
@@ -40,7 +45,7 @@ export function setup() {
this.socket = this.createHTTPServer();
setTimeout(this::this.cycle, 1);
let localIPv4 = this.getLocalIPv4();
this.print(`Server running at ${localIPv4}:${CFG.PORT}`);
this.print(`Server listening at ${localIPv4}:${CFG.PORT}`, 33);
this.emit("ready", void 0);
});
@@ -124,6 +129,7 @@ export function parseGameMaster() {
try {
let data = fs.readFileSync(CFG.DUMP_ASSET_PATH + "game_master");
master = this.parseProtobuf(data, "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
let Master = new GameMaster(master);
} catch (e) {
this.print(e, 31);
}

View File

@@ -1,6 +1,3 @@
import Long from "long";
import proto from "./proto";
import CFG from "../cfg";
/**
@@ -20,15 +17,6 @@ export function inherit(cls, prot) {
}
/**
* @param {Buffer} body
*/
export function decodeRequestEnvelope(body) {
return (
proto.Networking.Envelopes.RequestEnvelope.decode(body)
);
}
/**
* http://stackoverflow.com/a/7616484/3367904
* @param {String} str
@@ -45,18 +33,6 @@ export function getHashCodeFrom(str) {
return hash;
};
/**
* @param {Long} long
* @return {Number}
*/
export function decodeLong(long) {
let value = Long.fromBits(long.high, long.low, !!long.unsigned);
return (parseInt(value.toString()));
}
/**
* @return {Number}
*/
@@ -96,4 +72,11 @@ export function capitalize(str) {
return (
str[0].toUpperCase() + str.slice(1)
);
}
let rx_username = /[^a-z\d]/i;
export function validUsername(str) {
return (
!!(rx_username.test(str))
);
}

View File

@@ -1,84 +0,0 @@
"use strict";
var fs = require("fs");
var fse = require("fs-extra");
var git = require("nodegit");
var dirTree = require("directory-tree");
let tmpDir = "./tmp";
let cloneDir = JSON.parse(fs.readFileSync("./package.json")).repository.url;
let ignore = [".git", "cfg.js", "updater.js"];
function skip() {
return new Promise((resolve) => {
fse.removeSync(tmpDir);
console.log(`Skipped update to version ${newVersion}`);
resolve();
});
}
function updateProject() {
return new Promise((resolve) => {
let newFiles = dirTree("./tmp");
recurse(newFiles.children);
resolve();
});
}
function recurse(parent) {
for (let key in parent) {
let name = parent[key].name;
if (ignore.indexOf(name) > -1) continue;
let isDir = parent[key].hasOwnProperty("children");
try {
if (!isDir) {
fse.outputFileSync(parent[key].path.substring(4), fs.readFileSync(parent[key].path));
}
else {
recurse(parent[key].children);
}
} catch (e) { console.log(e); }
};
}
(function() {
return new Promise((resolve) => {
console.log("Preparing to update..");
setTimeout(() => {
fse.removeSync(tmpDir);
let currentVersion = JSON.parse(fs.readFileSync("./package.json")).version;
console.log(`Your current version is ${currentVersion}!`);
setTimeout(() => {
console.log("Fetching latest version..");
git.Clone(cloneDir, tmpDir).then((res, rofl) => {
let newVersion = null;
try {
newVersion = JSON.parse(fs.readFileSync(`${tmpDir}/package.json`)).version;
} catch (e) {
console.log("Version check failed!");
return resolve();
}
if (currentVersion === newVersion) {
console.log(`You are already running the latest version ${currentVersion}!`);
skip().then(resolve);
return void 0;
}
else if (currentVersion > newVersion) {
console.log(`Your version ${currentVersion} is newer than ${newVersion}!`);
skip().then(resolve);
return void 0;
}
console.log(`Latest version is ${newVersion}`);
console.log(`Updating to version ${newVersion}`);
updateProject().then(() => {
fse.removeSync(tmpDir);
console.log("Update successfully completed, please restart!");
resolve();
});
});
}, 2e3);
}, 1e3);
});
})();