Initial commit

This commit is contained in:
Felix 2016-08-27 13:12:21 +02:00
parent 59c2bc0767
commit 00e2ed3fa7
49 changed files with 396 additions and 2629 deletions

View File

@ -1,3 +0,0 @@
{
"presets": ["es2015", "stage-0"]
}

16
.gitattributes vendored
View File

@ -1,16 +0,0 @@
# Line endings: enforce LF in GitHub, convert to native on checkout.
* text=auto
*.js text
# Make GitHub ignore vendor libraries while computing language stats.
# See https://github.com/github/linguist#overrides.
*.proto linguist-vendored=true
*.sh linguist-vendored=true
*.bat linguist-vendored=true
# Explicitly specify language for non-standard extensions used under
# ide/web/lib/templates to make GitHub correctly count their language stats.
#
*.js_ linguist-language=JavaScript

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
node_modules/
scripts/
data/

6
.greet
View File

@ -1,6 +0,0 @@
______ _____ _____ _____
| ___ \ _ | __ \ _ |
| |_/ / | | | | \/ | | | ___ ___ _ ____ _____ _ __
| __/| | | | | __| | | |/ __|/ _ \ '__\ \ / / _ \ '__|
| | \ \_/ / |_\ \ \_/ /\__ \ __/ | \ V / __/ |
\_| \___/ \____/\___/ |___/\___|_| \_/ \___|_|

8
.help
View File

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

View File

@ -1,7 +0,0 @@
sudo: false
language: node_js
script: "npm run test"
node_js:
- "4"
- "5"
- "6"

View File

@ -1,60 +0,0 @@
````
______ _____ _____ _____
| ___ \ _ | __ \ _ |
| |_/ / | | | | \/ | | | ___ ___ _ ____ _____ _ __
| __/| | | | | __| | | |/ __|/ _ \ '__\ \ / / _ \ '__|
| | \ \_/ / |_\ \ \_/ /\__ \ __/ | \ V / __/ |
\_| \___/ \____/\___/ |___/\___|_| \_/ \___|_|
````
<div align="center">
<a href="#">
<img src="https://img.shields.io/badge/Pokemon%20GO-0.35.0-blue.svg?style=flat-square" />
</a>
<a href="https://discord.gg/gu8ZUJp">
<img src="https://img.shields.io/badge/Discord-Join%20Chat%20%E2%86%92-738bd7.svg?style=flat-square" />
</a>
<a href="https://nodejs.org/api/documentation.html#documentation_stability_index">
<img src="https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square" alt="Stability" />
</a>
</div>
<img width="25%" src="http://image.prntscr.com/image/55fb47b99164465abefb2698a7bb142d.png" />
<img width="24%" src="http://image.prntscr.com/image/0ab416fa479f427180476cad8a238f04.png" />
<img width="24%" src="http://image.prntscr.com/image/918383bb5cde453ab2572461084b4601.png" />
<img width="25%" src="http://i.imgur.com/iZypeny.png" />
# Getting started
## Setup
Copy and rename ``cfg.js.example`` to ``cfg.js``.
Open ``cfg.js`` and fill the following fields:
````js
DOWNLOAD_PROVIDER: "GOOGLE";
DOWNLOAD_USERNAME: "USERNAME";
DOWNLOAD_PASSWORD: "PASSWORD";
````
## Tunneling setup
The pokemon go app traffic has to get forwarded manually to this custom server. Download [rastapasta](https://github.com/rastapasta)'s [Pokemon Go Xposed](https://github.com/rastapasta/pokemon-go-xposed/releases) app and follow the installation instructions [here](https://github.com/rastapasta/pokemon-go-xposed#how-to-use-it).
## Database setup
To setup a database connection, open ``cfg.js`` and change the database login credentials:
````js
MYSQL_PORT: 3306,
MYSQL_HOST_IP: "127.0.0.1",
MYSQL_DB_NAME: "pogosql",
MYSQL_USERNAME: "root",
MYSQL_PASSWORD: "",
````
The required database tables get generated automatically.
## Server setup
You need at minimum [Node.js](https://nodejs.org/en/) version 6.x.
Depending on your OS, you need to run either ``run-linux.sh`` or ``run-windows.bat`` from the root folder.

22
ajax.js Normal file
View File

@ -0,0 +1,22 @@
function send(data, resolve) {
var xhr = new XMLHttpRequest();
var protocol = window.location.protocol;
xhr.open("POST", protocol + "//" + "127.0.0.1:3000/api", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
if (typeof resolve === "function") {
try {
resolve(JSON.parse(xhr.responseText));
} catch (e) {
resolve(void 0);
}
}
} else {
resolve(xhr.statusText);
}
}
};
xhr.send(JSON.stringify(data));
}

View File

@ -1,58 +0,0 @@
import fs from "fs";
export default {
VERSION: JSON.parse(fs.readFileSync("./package.json")).version,
// show greeting
GREET: true,
// emit api calls
ENABLE_API: false,
// Server settings
MAX_CONNECTIONS: 64,
PORT: 3000,
// If using vmware, vps or multiple network adapters, set the related ip here
// otherwise leave it blank
LOCAL_IP: "",
GAME_MODE: 0,
SAVE_INTERVAL: 6e4,
// Better dont touch these
TICK_INTERVAL: 1,
// Timeouts
BOOT_TIMEOUT: 1e4,
PLAYER_CONNECTION_TIMEOUT: 1e3 * 60 * 30,
MINIMUM_CLIENT_VERSION: "0.35.0",
DEFAULT_CONSOLE_COLOR: 32,
TRANSFER_ACCOUNTS: false,
// Server debug options
DEBUG_DUMP_PATH: "logs/",
DEBUG_DUMP_TRAFFIC: true,
DEBUG_LOG_REQUESTS: true,
// Choose a database type
DATABASE_TYPE: "MYSQL",
// MySQL credentials
MYSQL_PORT: 3306,
MYSQL_HOST_IP: "127.0.0.1",
MYSQL_DB_NAME: "pogosql",
MYSQL_USERNAME: "root",
MYSQL_PASSWORD: "",
MYSQL_USERS_TABLE: "users",
MYSQL_OWNED_PKMN_TABLE: "owned_pkmn",
// Used for asset download session
DOWNLOAD_PROVIDER: "GOOGLE",
DOWNLOAD_USERNAME: "USERNAME",
DOWNLOAD_PASSWORD: "PASSWORD",
// Google maps api key
GMAPS_KEY: "AIzaSyDF9rkP8lhcddBtvH9gVFzjnNo13WtmJIM",
// Currently supported pokemon
MAX_POKEMON_NATIONAL_ID: 151,
DUMP_ASSET_PATH: "data/"
}

240
css/main.css Normal file
View File

@ -0,0 +1,240 @@
html {
-webkit-animation: fadein 1s;
-moz-animation: fadein 1s;
-ms-animation: fadein 1s;
-o-animation: fadein 1s;
animation: fadein 1s;
}
body {
overflow-x: hidden;
}
.view {
letter-spacing: 0px;
padding: 5px 25px !important;
margin-top: -35px;
}
.area {
font-family: "Andale Mono", AndaleMono, monospace;
text-align: center;
font-style: normal;
font-variant: normal;
-webkit-font-smoothing: antialiased;
font-size: 75px;
letter-spacing: -5px;
color: #fff;
position: relative;
margin-top: 5px;
text-transform: uppercase;
}
.Codemirror {
text-align: left;
}
.version {
font-size: 15px;
letter-spacing: 0px;
margin-top: -75px;
margin-bottom: -25px;
text-transform: none;
}
.btn {
text-transform: uppercase;
}
.centered {
text-align: center;
position: relative;
top: 40%;
transform: translateY(-40%);
margin-top: -175px;
-webkit-transform: translateY(-40%);
-moz-transform: translateY(0%);
}
@-moz-document url-prefix() {
.centered {
margin-top: 0px;
}
}
.body {
background: #2d2d2d;
background-color: #2d2d2d;
}
.star {
position: absolute;
width: 2px;
height: 2px;
background: rgba(255, 255, 255, 0.45);
opacity: 1;
}
.btn {
font-family: "Andale Mono", AndaleMono, monospace;
display: inline-block;
padding: 5px;
border: 1px solid rgba(255, 255, 255, .35);
border-radius: 4px;
color: rgba(255, 255, 255, .75);
text-decoration: none;
transition: border .35s, background .35s;
min-width: 100px;
text-align: center;
font-size: 15px;
font-style: normal;
font-variant: normal;
font-weight: 500;
line-height: 25px;
cursor: pointer;
}
.input {
background: rgba(0,0,0,0);
cursor: auto;
}
input:focus {
outline: none;
}
button:focus {
outline: none;
}
.label {
background: rgba(255, 255, 255, .05);
border: 1px solid rgba(255, 255, 255, .5);
color: #79a2b7;
}
.info {
padding-bottom: 45px;
margin-top: -45px;
font-size: 18px;
letter-spacing: 0px;
}
.cmd_label {
border: none;
background: rgba(255,255,255,0.05);
color: white;
cursor: auto;
text-transform: none;
}
.submit {
background: rgba(165, 165, 165, 0.15);
}
.with_label {
margin-left: 25px;
width: 120px;
}
#connection_status {
text-transform: uppercase;
}
.login_area {
font-size: 25px;
letter-spacing: 0px;
text-transform: none;
margin: -25px;
padding: 0px;
}
.login_input {
text-transform: none;
background: rgba(0,0,0,0);
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn:hover {
background: rgba(255, 255, 255, .05);
border: 1px solid rgba(255, 255, 255, .5);
}
.txt {
margin-left: calc(20%);
margin-right: calc(20%);
left: auto;
width: auto;
min-height: 300px;
background: rgba(255, 255, 255, 0.0) !important;
border: 1px solid rgba(255, 255, 255, 0.0) !important;
border-radius: 4px !important;
padding: 10px 15px !important;
color: rgba(255, 255, 255, .75) !important;
resize: none;
transition: color .35s !important;
}
.txt:focus {
outline: none;
color: rgba(255, 255, 255, .85);
}
::-moz-selection {
color: rgba(255, 255, 255, .85);
background: rgba(255, 255, 255, .075);
}
::selection {
color: rgba(255, 255, 255, .85);
background: rgba(255, 255, 255, .075);
}
::-webkit-scrollbar{
width: 10px;
height: 0px;
background: transparent;
}
::-webkit-scrollbar-thumb{
background: rgba(255, 255, 255, .15);
border-radius: 5px;
}
::-webkit-scrollbar-corner{
background: transparent;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
@-webkit-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
@-moz-keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes pulsate {
0% {transform: scale(0.1, 0.1); opacity: 0.0;}
50% {opacity: 1.0;}
100% {transform: scale(1.2, 1.2); opacity: 0.0;}
}
@-webkit-keyframes pulsate {
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
50% {opacity: 1.0;}
100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
}
@-moz-keyframes pulsate {
0% {transform: scale(0.1, 0.1); opacity: 0.0;}
50% {opacity: 1.0;}
100% {transform: scale(1.2, 1.2); opacity: 0.0;}
}

23
css/pure.min.css vendored Normal file

File diff suppressed because one or more lines are too long

39
index.html Normal file
View File

@ -0,0 +1,39 @@
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Language" content="en">
<meta name="viewport" content="width=device-width">
<meta content="origin-when-cross-origin" name="referrer" />
<title>POGOserver api</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/main.css">
<link rel="stylesheet" type="text/css" href="css/pure.min.css">
</head>
<body class="body">
<div class="area">
<p>POGOserver</p>
<p id="version" class="version"> </p>
<p><button class="btn color-1 view login_input" id="connection_status" href="#" style="color:yellow;">Connecting..</button></p>
</div>
<div id="login_area" class="area">
<p class="login_area">Login</p>
<p><input class="btn color-1 view input login_input" id="login_username" style="margin:-20px;" autocomplete="new-password" value="root"></input></p>
<p><input class="btn color-1 view input login_input" id="login_password" type="password" autocomplete="new-password"></input></p>
<p><button class="btn color-1 view login_input" id="login_attempt">Login</button></p>
</div>
<div id="world_manager" class="area" style="display:none;">
<p class="info" id="server_version">Server version: v0.1.0</p>
<p class="info" id="connected_players">Connected players: 0</p>
<p class="login_area" style="padding-bottom: 15px;">World Manager</p>
<p><button class="btn color-1 view cmd_label label">Spawn</button><input class="btn color-1 view input login_input with_label" id="spawn_user" placeholder="Username" autocomplete="new-password"></input><input class="btn color-1 view input login_input with_label" autocomplete="new-password" id="spawn_pkmn" placeholder="Pokemon"></input><button id="submit_spawn" class="btn color-1 view login_input with_label submit">Submit</button></p>
</div>
<script language="javascript" src="ajax.js"></script>
<script language="javascript" src="main.js"></script>
</body>
</html>

View File

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

72
main.js Normal file
View File

@ -0,0 +1,72 @@
var loggedIn = false;
var loginTimeout = null;
function setStatus(txt, color) {
connection_status.innerHTML = txt;
connection_status.style.color = color;
}
setStatus("Connecting", "yellow");
send({
action: "init"
}, function(res) {
if (res.success) {
setStatus("Connected!", "green");
}
else {
setStatus("Connection failed!", "red");
return void 0;
}
});
login_attempt.addEventListener("click", function() {
var username = login_username.value;
var password = login_password.value;
send({
action: "login",
username: username,
password: password
}, function(res) {
if (res.success) {
login();
}
else {
setStatus("Login failed!", "red");
clearTimeout(loginTimeout);
loginTimeout = setTimeout(function() {
setStatus("Connected!", "green");
}, 3e3);
}
});
});
submit_spawn.addEventListener("click", function() {
send({
action: "spawnPkmnToPlayer",
player: spawn_user.value,
pkmn: spawn_pkmn.value
}, function(res) {
console.log(res);
});
});
function login() {
loggedIn = true;
login_area.style.display = "none";
setStatus("Logged in!", "green");
world_manager.style.display = "block";
send({
action: "getConnectedPlayers"
}, function(res) {
connected_players.innerHTML = "Connected players: " + res.connected_players;
});
send({
action: "getServerVersion"
}, function(res) {
server_version.innerHTML = "Server version: v" + res.version;
});
}

View File

@ -1,32 +0,0 @@
{
"name": "POGOServer",
"version": "0.5.0",
"description": "",
"repository": {
"type": "git",
"url": "git://github.com/maierfelix/POGOServer.git"
},
"scripts": {
"test": "echo \"Error: no test specified\"",
"babel-node": "babel-node --presets=es2015",
"start": "npm run babel-node -- ./src/index.js"
},
"engines": {
"node": ">= 6.x",
"npm": ">= 3.x"
},
"author": "Felix Maier",
"license": "MIT",
"dependencies": {
"babel-cli": "^6.11.4",
"babel-preset-es2015": "^6.13.1",
"babel-preset-stage-0": "^6.5.0",
"fs-extra": "^0.30.0",
"mysql": "^2.11.1",
"jwt-decode": "^2.1.0",
"pogo-asset-downloader": "^0.3.1",
"pokemongo-protobuf": "^1.11.0",
"pcrypt": "git+https://github.com/laverdet/pcrypt.git"
},
"devDependencies": {}
}

View File

@ -1,10 +0,0 @@
#!/bin/bash
pause() {
read -p "Press [Enter] key to exit"
}
cd $(dirname $0)
npm install
npm run start

View File

@ -1,2 +0,0 @@
npm run start
pause

View File

@ -1,44 +0,0 @@
import CFG from "../cfg";
export function ready(e) {
if (e) console.log(e);
else console.log("Ready!");
}
/**
* @param {String} msg
* @param {Number} color
* @param {Boolean} nl
*/
export function print(msg, color, newline) {
color = Number.isInteger(color) ? color : CFG.DEFAULT_CONSOLE_COLOR;
process.stdout.write(`[Console] \x1b[${color};1m${msg}\x1b[0m${newline === void 0 ? "\n" : ""}`);
}
/**
* @param {Player} player
*/
export function registerPlayer(player) {
console.log(player.username + " registered!");
}
/**
* @param {Player} player
*/
export function loginPlayer(player) {
console.log(player.username + " logged in!");
}
/**
* @param {Player} player
*/
export function killPlayer(player) {
console.log(player.username + " killed!");
}
/**
* @param {Player} player
*/
export function updatePlayerAvatar(player) {
console.log("Updated avatar of " + player.username + "!");
}

View File

@ -1,75 +0,0 @@
import CFG from "../cfg";
export function startCycle() {
this.cycleInstance = setTimeout(() => this.cycle(), CFG.TICK_INTERVAL);
}
export function stopCycle() {
clearTimeout(this.cycleInstance);
}
export function cycle() {
this.stopCycle();
this.startCycle();
if (this.STATES.PAUSE === true) return void 0;
if (this.STATES.CRASH === true) return void 0;
this.updateTimers();
if (this.passedTicks <= 0) return void 0;
this.resetTimers();
return void 0;
}
export function updateTimers() {
let local = Date.now();
this.passedTicks = local - this.time;
this.tick += this.passedTicks;
this.time = local;
return void 0;
}
export function resetTimers() {
if (this.tick >= 25) {
this.fullTick++;
if (this.fullTick >= 2) {
this.fullTick = 0;
}
this.tick = 0;
// Player timeout tick, not precise
this.playerTimeoutTick();
}
this.saveTick++;
// Save interval
if (this.saveTick >= CFG.SAVE_INTERVAL) {
//this.saveAllPlayers();
this.saveTick = 0;
}
return void 0;
}
export function playerTimeoutTick() {
let player = null;
let maxTimeout = CFG.PLAYER_CONNECTION_TIMEOUT;
let players = this.world.players;
let ii = 0;
let length = players.length;
for (; ii < length; ++ii) {
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,48 +0,0 @@
import fs from "fs";
import CFG from "../../cfg";
export function createTableIfNotExists(name) {
return new Promise((resolve) => {
this.db.instance.query(`SHOW TABLES LIKE '${name}';`, (e, rows, fields) => {
if (e) console.log(e);
else {
// exists
if (rows && rows.length) resolve();
// create user table
else this.createTables().then(resolve);
}
});
});
}
/**
* @param {String} name
*/
export function createTables() {
return new Promise((resolve) => {
this.createTable(CFG.MYSQL_USERS_TABLE).then(() => {
this.createTable(CFG.MYSQL_OWNED_PKMN_TABLE).then(() => {
resolve();
});
});
});
}
export function createTable(name) {
this.print(`Creating table ${name}`, 36);
let query = `
CREATE TABLE IF NOT EXISTS ${name} (
${fs.readFileSync(__dirname + "/tables/" + name + ".table", "utf8")}
) ENGINE=InnoDB;
`;
return new Promise((resolve) => {
this.db.instance.query(query, (e, rows) => {
if (e) console.log(e);
else resolve();
});
});
}

View File

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

View File

@ -1,45 +0,0 @@
import mysql from "mysql";
import CFG from "../../cfg";
export function setupDatabaseConnection() {
let connection = mysql.createConnection({
host : CFG.MYSQL_HOST_IP,
port : CFG.MYSQL_PORT,
database : CFG.MYSQL_DB_NAME,
user : CFG.MYSQL_USERNAME,
password : CFG.MYSQL_PASSWORD
});
return new Promise((resolve) => {
connection.connect((error) => {
if (error) {
this.print("MySQL " + error, 31);
this.retry("Retrying again in ", () => this.setupDatabaseConnection().then(resolve), 5);
return void 0;
}
this.db.instance = connection;
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();
});
});
});
connection.on("error", (error) => {
this.print("MySQL " + error, 31);
this.retry("Trying to reconnect in ", () => this.setupDatabaseConnection().then(resolve), 5);
});
});
}
/**
* @param {Function} resolve
*/
export function closeConnection(resolve) {
this.db.instance.end(() => {
resolve();
});
}

View File

@ -1,227 +0,0 @@
import CFG from "../../cfg";
/**
* @return {String}
*/
export function getUserQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_USERS_TABLE}
SET
username=?,
email=?,
exp=?,
level=?,
stardust=?,
pokecoins=?,
team=?,
latitude=?,
longitude=?,
altitude=?,
send_marketing_emails=?,
send_push_notifications=?,
skin=?,
hair=?,
shirt=?,
pants=?,
hat=?,
shoes=?,
eyes=?,
gender=?,
backpack=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getUserQueryData(obj) {
return ([
obj.username,
obj.email,
obj.exp,
obj.level,
obj.stardust,
obj.pokecoins,
obj.team,
// position
obj.latitude,
obj.longitude,
obj.altitude,
// contact settings
obj.send_marketing_emails,
obj.send_push_notifications,
// avatar
obj.skin,
obj.hair,
obj.shirt,
obj.pants,
obj.hat,
obj.shoes,
obj.eyes,
obj.gender,
obj.backpack,
// WHERE
obj.email
]);
}
/**
* @return {String}
*/
export function getOwnedPkmnQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_OWNED_PKMN_TABLE}
SET
owner_id=?,
pokemon_id=?,
cp=?,
stamina=?,
stamina_max=?,
move_1=?,
move_2=?,
deployed_fort_id=?,
is_egg=?,
egg_km_walked_target=?,
egg_km_walked_start=?,
origin=?,
height_m=?,
weight_kg=?,
individual_attack=?,
individual_defense=?,
individual_stamina=?,
cp_multiplier=?,
pokeball=?,
captured_cell_id=?,
battles_attacked=?,
battles_defended=?,
egg_incubator_id=?,
creation_time_ms=?,
num_upgrades=?,
additional_cp_multiplier=?,
favorite=?,
nickname=?,
from_fort=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getOwnedPkmnQueryData(obj) {
return ([
obj.owner_id,
obj.pokemon_id,
obj.cp,
obj.stamina,
obj.stamina_max,
obj.move_1,
obj.move_2,
obj.deployed_fort_id || "",
obj.is_egg || 0,
obj.egg_km_walked_target || 0,
obj.egg_km_walked_start || 0,
obj.origin || 0,
obj.height_m,
obj.weight_kg,
obj.individual_attack,
obj.individual_defense,
obj.individual_stamina,
obj.cp_multiplier,
obj.pokeball,
obj.captured_cell_id || 0,
obj.battles_attacked || 0,
obj.battles_defended || 0,
obj.egg_incubator_id || "",
obj.creation_time_ms,
obj.num_upgrades || 0,
obj.additional_cp_multiplier || 0,
obj.favorite || 0,
obj.nickname || "",
obj.from_fort || 0
]);
}
export function getUserItemQuery(cmd, after) {
return (`
${cmd} ${CFG.MYSQL_USERS_TABLE}
SET
item_poke_ball=?,
item_great_ball=?,
item_ultra_ball=?,
item_master_ball=?,
item_potion=?,
item_super_potion=?,
item_hyper_potion=?,
item_max_potion=?,
item_revive=?,
item_max_revive=?,
item_lucky_egg=?,
item_incense_ordinary=?,
item_incense_spicy=?,
item_incense_cool=?,
item_incense_floral=?,
item_troy_disk=?,
item_razz_berry=?,
item_bluk_berry=?,
item_nanab_berry=?,
item_wepar_berry=?,
item_pinap_berry=?,
item_incubator_basic=?,
item_incubator_basic_unlimited=?,
item_pokemon_storage_upgrade=?,
item_storage_upgrade=?
${after}
`);
}
/**
* @param {Object} obj
* @return {Array}
*/
export function getUserItemQueryData(obj) {
let items = [];
for (let key in obj.items) {
items.push(obj.items[key]);
};
let email = obj.email;
obj = obj.items;
return ([
obj.poke_ball,
obj.great_ball,
obj.ultra_ball,
obj.master_ball,
obj.potion,
obj.super_potion,
obj.hyper_potion,
obj.max_potion,
obj.revive,
obj.max_revive,
obj.lucky_egg,
obj.incense_ordinary,
obj.incense_spicy,
obj.incense_cool,
obj.incense_floral,
obj.troy_disk,
obj.razz_berry,
obj.bluk_berry,
obj.nanab_berry,
obj.wepar_berry,
obj.pinap_berry,
obj.incubator_basic,
obj.incubator_basic_unlimited,
obj.pokemon_storage_upgrade,
obj.storage_upgrade,
// WHERE
email
]);
}

View File

@ -1,31 +0,0 @@
id int(11) NOT NULL AUTO_INCREMENT,
owner_id int(11) NOT NULL,
pokemon_id varchar(32) NOT NULL,
cp int(32) NOT NULL,
stamina int(11) NOT NULL,
stamina_max int(11) NOT NULL,
move_1 varchar(32) NOT NULL,
move_2 varchar(32) NOT NULL,
deployed_fort_id longtext NOT NULL,
is_egg tinyint(1) NOT NULL,
egg_km_walked_target double NOT NULL,
egg_km_walked_start double NOT NULL,
origin int(11) NOT NULL,
height_m double NOT NULL,
weight_kg double NOT NULL,
individual_attack int(11) NOT NULL,
individual_defense int(11) NOT NULL,
individual_stamina int(11) NOT NULL,
cp_multiplier double NOT NULL,
pokeball varchar(32) NOT NULL,
captured_cell_id varchar(32) NOT NULL,
battles_attacked int(11) NOT NULL,
battles_defended int(11) NOT NULL,
egg_incubator_id longtext NOT NULL,
creation_time_ms bigint(20) NOT NULL,
num_upgrades int(11) NOT NULL,
additional_cp_multiplier double NOT NULL,
favorite tinyint(1) NOT NULL,
nickname longtext NOT NULL,
from_fort int(11) NOT NULL,
PRIMARY KEY (id)

View File

@ -1,54 +0,0 @@
id int(11) NOT NULL AUTO_INCREMENT,
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 double NOT NULL,
send_marketing_emails tinyint(1) NOT NULL,
send_push_notifications tinyint(1) 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,
item_master_ball int(11) NOT NULL,
item_potion int(11) NOT NULL,
item_super_potion int(11) NOT NULL,
item_hyper_potion int(11) NOT NULL,
item_max_potion int(11) NOT NULL,
item_revive int(11) NOT NULL,
item_max_revive int(11) NOT NULL,
item_lucky_egg int(11) NOT NULL,
item_incense_ordinary int(11) NOT NULL,
item_incense_spicy int(11) NOT NULL,
item_incense_cool int(11) NOT NULL,
item_incense_floral int(11) NOT NULL,
item_troy_disk int(11) NOT NULL,
item_razz_berry int(11) NOT NULL,
item_bluk_berry int(11) NOT NULL,
item_nanab_berry int(11) NOT NULL,
item_wepar_berry int(11) NOT NULL,
item_pinap_berry int(11) NOT NULL,
item_incubator_basic int(11) NOT NULL,
item_incubator_basic_unlimited int(11) NOT NULL,
item_pokemon_storage_upgrade int(11) NOT NULL,
item_storage_upgrade int(11) NOT NULL,
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)

View File

@ -1,75 +0,0 @@
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);
}
}

View File

@ -1,39 +0,0 @@
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,190 +0,0 @@
import fs from "fs";
import os from "os";
import EventEmitter from "events";
import POGOProtos from "pokemongo-protobuf";
import {
inherit,
_toCC
} from "./utils";
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 _request from "./request";
import * as _response from "./response";
import * as _process from "./process";
import * as _mysql from "./db/index";
import * as _mysql_get from "./db/get";
import * as _mysql_query from "./db/query";
import * as _mysql_create from "./db/create";
const greetMessage = fs.readFileSync(".greet", "utf8");
/**
* @class GameServer
*/
export default class GameServer extends EventEmitter {
/** @constructor */
constructor() {
super(null);
this.STATES = {
PAUSE: false,
DEBUG: false,
CRASH: false
};
this.db = {
instance: null,
collections: {}
};
this.assets = {};
this.master = null;
this.socket = null;
this.cycleInstance = null;
// Timer things
this.tick = 0;
this.time = 0;
this.fullTick = 0;
this.saveTick = 0;
this.timeoutTick = 0;
this.passedTicks = 0;
this.initAPI();
if (CFG.GREET) this.greet();
this.print(`Booting Server v${require("../package.json").version}-dev`, 33);
this.world = new World(this);
this.setup();
}
initAPI() {
if (CFG.ENABLE_API) {
for (let key in _api) {
this.on(key, _api[key]);
};
}
// make sure we still have our print fn
else {
this.on("print", _api["print"]);
}
}
/**
* @param {String} msg
* @param {Number} color
* @param {Boolean} nl
*/
print(msg, color, nl) {
this.emit("print", msg, color, nl);
}
/**
* @param {String} msg
* @param {Function} fn
* @param {Number} 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, fn, --timer), 1e3);
else {
process.stdout.write("\n");
fn();
}
}
/**
* @return {String}
*/
getLocalIPv4() {
let address = null;
let interfaces = os.networkInterfaces();
for (var dev in interfaces) {
interfaces[dev].filter((details) => details.family === "IPv4" && details.internal === false ? address = details.address: void 0);
};
return (address);
}
/**
* @param {Buffer} buffer
* @param {String} schema
*/
parseProtobuf(buffer, schema) {
try {
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);
} catch (e) {
return (false);
}
return (true);
}
greet() {
console.log(greetMessage);
}
}
inherit(GameServer, _dump);
inherit(GameServer, _http);
inherit(GameServer, _setup);
inherit(GameServer, _cycle);
inherit(GameServer, _request);
inherit(GameServer, _response);
inherit(GameServer, _process);
inherit(GameServer, _mysql);
inherit(GameServer, _mysql_get);
inherit(GameServer, _mysql_query);
inherit(GameServer, _mysql_create);
(() => {
const server = new GameServer();
process.openStdin().addListener("data", (data) => {
server.stdinInput(data);
});
process.on("uncaughtException", (data) => {
server.uncaughtException(data);
});
})();

View File

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

View File

@ -1,63 +0,0 @@
/**
* @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

@ -1,123 +0,0 @@
/**
* @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

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

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

@ -1,91 +0,0 @@
/**
* @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

@ -1,65 +0,0 @@
/**
* @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

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

@ -1,105 +0,0 @@
import POGOProtos from "pokemongo-protobuf";
export function GetInventory() {
let stats = this.GetInventoryPlayer();
let items = this.GetInventoryItems();
let party = this.GetInventoryParty();
let buffer = ({
success: true,
inventory_delta: {
new_timestamp_ms: new Date().getTime(),
inventory_items: stats.concat(items).concat(party)
}
});
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetInventoryResponse"));
}
export function GetInventoryPlayer() {
let player = this.player;
return ({
modified_timestamp_ms: new Date().getTime(),
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
}
}
});
}
export function GetInventoryItems() {
let player = this.player;
let items = [];
let match = "item_";
for (let key in player) {
if (key.substring(0, 5) === match) {
items.push({
modified_timestamp_ms: new Date().getTime(),
inventory_item_data: {
item: {
item_id: key.toUpperCase(),
count: parseFloat(player[key])
}
}
});
}
};
return (items);
}
export function GetInventoryParty() {
let player = this.player;
let pkmns = [];
for (let pkmn of player.party) {
pkmns.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
}
}
});
};
return (pkmns);
}

View File

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

View File

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

View File

@ -1,28 +0,0 @@
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;
}
}

View File

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

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

View File

@ -1,124 +0,0 @@
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,18 +0,0 @@
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Request} request
*/
export function GetMapObject(request) {
let player = this.player;
let latitude = player.latitude;
let longitude = player.longitude;
return new Promise(() => {
// db call
//
});
}

View File

@ -1,76 +0,0 @@
import fs from "fs";
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 "/players":
var length = players.length;
this.print(`${length}:${CFG.MAX_CONNECTIONS} connected players!`, 33);
break;
// Exit the server
case "/exit":
this.shutdown();
break;
case "/kick":
this.kickPlayer(data[1]);
break;
case "/killall":
var length = players.length;
this.removeAllPlayers();
var result = length - players.length;
this.print(`Removed ${result} player${result === 1 ? "": "s"}!`);
break;
case "/clear":
process.stdout.write("\x1Bc");
this.greet();
break;
case "/help":
console.log("\x1b[36;1m==================================== HELP =====================================\x1b[0m");
console.log(`\x1b[${CFG.DEFAULT_CONSOLE_COLOR};1m${helpMessage}\x1b[0m`);
console.log("\x1b[36;1m===============================================================================\x1b[0m");
break;
case "/save":
this.saveAllPlayers();
var length = players.length;
this.print(`Saved ${length} player${length === 1 ? "": "s"} into database!`);
break;
case "/spawn":
this.spawnPkmnAtPlayer(data[1], data[2], data[3] || 1);
break;
case "/update":
eval(fs.readFileSync("update.js", "utf8"));
break;
default:
this.print(`${cmd} is not a valid command!`, 31);
break;
};
};
export function stdinInput(data) {
data = data.toString().substring(0, data.length - 2);
if (data.length < 1) return void 0;
data = data.split(" ");
var cmd = data[0];
this.processCommand(cmd, data);
};
export function uncaughtException(excp) {
switch (excp.errno) {
case "EADDRINUSE":
this.print(`Port ${CFG.PORT} is already in use!`, 31);
break;
case "EACCES":
this.print("No root privileges!", 31);
break;
default:
console.log("Unhandled exception occurred: ", excp.code);
console.log(excp.stack);
break;
};
this.print("The server has crashed!", 31);
};

View File

@ -1,157 +0,0 @@
import fs from "fs";
import url from "url";
import pcrypt from "pcrypt";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
/**
* @param {Player} player
* @param {Request} req
* @param {Response} res
*/
export function routeRequest(player, req, res) {
let parsed = url.parse(req.url).pathname;
let route = parsed.split("/");
let host = req.headers.host;
switch (route[1]) {
case "plfe":
case "custom":
if (route[2] === "rpc") this.onRequest(player, req);
break;
case "model":
// make sure no random dudes can access download
if (!player.authenticated) return void 0;
let name = route[2];
if (name && name.length > 1) {
let folder = player.isAndroid ? "android/" : "ios/";
fs.readFile("data/" + folder + name, (error, data) => {
if (error) {
this.print(`Error file resolving model ${name}:` + error, 31);
return void 0;
}
this.print(`Sent ${name} to ${player.email}`, 36);
res.end(data);
});
}
break;
default:
console.log(`Unknown request url: https://${req.headers.host}${req.url}`);
break;
};
}
/**
* @param {Player} player
* @param {Request} req
*/
export function onRequest(player, req) {
let request = this.parseProtobuf(req.body, "POGOProtos.Networking.Envelopes.RequestEnvelope");
request.requests = request.requests || [];
if (CFG.DEBUG_LOG_REQUESTS) {
console.log("#####");
request.requests.map((request) => {
console.log("Got request:", request.request_type);
}).join(",");
}
if (!player.authenticated) {
player.sendResponse(this.authenticatePlayer(player));
return void 0;
}
if (!request.requests.length) {
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);
player.sendResponse(msg);
});
}
/**
* @param {Number} status
* @param {Array} returns
* @param {Request} req
* @param {Player} player
* @param {Boolean} auth
* @return {Buffer}
*/
export function envelopResponse(status, returns, req, player, auth) {
let buffer = req;
delete buffer.requests;
buffer.returns = returns;
// get players device platform one time
if (player.hasSignature === false && buffer.unknown6 && buffer.unknown6.unknown2) {
let sig = this.parseSignature(buffer);
if (sig.device_info !== void 0) {
player.isIOS = sig.device_info.device_brand === "Apple";
player.isAndroid = !player.isIOS;
player.hasSignature = true;
player.asset_digest = this.assets[player.isAndroid ? "android" : "ios"];
this.print(`${player.email} is playing with an ${player.isIOS ? "Apple" : "Android"} device!`, 36);
}
}
if (auth) buffer.auth_ticket = AuthTicket();
if (buffer.unknown6) {
buffer.unknown6 = [{
"response_type": 6,
"unknown2": {
"unknown1": "1",
"items": [],
"player_currencies": []
}
}];
}
buffer.status_code = status;
return (
POGOProtos.serialize(buffer, "POGOProtos.Networking.Envelopes.ResponseEnvelope")
);
}
/**
* @param {Player} player
* @param {Array} requests
* @return {Array}
*/
export function processRequests(player, requests) {
return new Promise((resolve) => {
let index = 0;
let length = requests.length;
let body = [];
const loop = (index) => {
this.processResponse(player, requests[index]).then((request) => {
body.push(request);
if (++index >= length) resolve(body);
else return loop(index);
});
};
loop(0);
});
}

View File

@ -1,54 +0,0 @@
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
import {
_toCC,
validUsername
} from "./utils";
/**
* @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
* @param {Request} req
* @return {Buffer}
*/
export function processResponse(player, req) {
let buffer = null;
let cc = _toCC(req.request_type);
let msg = this.parseMessage(req);
return new Promise((resolve) => {
try {
switch (req.request_type) {
default:
this.print(`Unknown request: ${req.request_type}`, 31);
break;
};
} catch (e) {
this.print(`Response error: ${e}`, 31);
};
resolve(buffer);
});
}

View File

@ -1,238 +0,0 @@
import fs from "fs";
import fse from "fs-extra";
import pogo from "pogo-asset-downloader";
import POGOProtos from "pokemongo-protobuf";
import CFG from "../cfg";
import * as master from "./master";
import GameMaster from "./models/GameMaster";
import {
capitalize,
idToPkmnBundleName
} from "./utils";
export function setup() {
let isFirstRun = !this.fileExists(CFG.DUMP_ASSET_PATH);
if (isFirstRun) {
this.print("Required assets are missing! Preparing dump session..", 31);
setTimeout(() => {
this.onFirstRun(() => {
this.setup();
});
}, 1e3);
return void 0;
}
// make sure all assets got loaded properly
this.validateAssets().then(() => {
this.print(`Downloaded assets are valid! Proceeding..`);
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) {
this.print("Invalid port!", 31);
return void 0;
}
this.socket = this.createHTTPServer();
setTimeout(this::this.cycle, 1);
let localIPv4 = this.getLocalIPv4();
this.print(`Server listening at ${localIPv4}:${CFG.PORT}`, 33);
this.emit("ready", void 0);
});
}).catch((e) => {
//fse.removeSync(CFG.DUMP_ASSET_PATH);
this.print("Error: " + e + " was not found!", 31);
this.emit("ready", e);
});
}
/**
* Make sure all required
* assets got loaded properly
*/
export function validateAssets() {
return new Promise((resolve, reject) => {
// validate game master
if (!this.fileExists(CFG.DUMP_ASSET_PATH + "game_master")) {
return reject("File game_master");
}
this.validateModels().then(() => {
resolve();
}).catch((e) => {
reject(e);
});
});
}
export function validateModels() {
let max = CFG.MAX_POKEMON_NATIONAL_ID;
let limit = pogo.platforms.length;
return new Promise((resolve, reject) => {
const validate = (index) => {
let platform = pogo.platforms[index];
let name = platform.name;
let path = CFG.DUMP_ASSET_PATH + name + "/";
// ups, validate asset_digest's too
if (!this.fileExists(path + "asset_digest")) {
return reject(`${path}asset_digest`);
}
else {
let buffer = fs.readFileSync(path + "asset_digest");
this.assets[name] = {
buffer: buffer,
decode: this.parseProtobuf(buffer, "POGOProtos.Networking.Responses.GetAssetDigestResponse")
}
}
// validate models inside folder
let ii = 0;
while (++ii <= max) {
let id = idToPkmnBundleName(ii);
if (!this.fileExists(path + id)) {
return reject("Model " + id);
}
};
if (++index >= limit) {
resolve();
return void 0;
}
validate(index);
};
validate(0);
});
}
export function parseGameMaster() {
let master = null;
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);
}
return (master);
}
export function onFirstRun(resolve) {
// make sure to login first!
pogo.login({
provider: CFG.DOWNLOAD_PROVIDER, // google or ptc
username: CFG.DOWNLOAD_USERNAME,
password: CFG.DOWNLOAD_PASSWORD
}).then(() => {
this.downloadAssetDigests().then(() => {
this.downloadAssets().then(resolve);
});
}).catch((e) => {
this.print(e, 31);
});
}
export function downloadAssetDigests(assets) {
return new Promise((resolve, reject) => {
// create data folder for each support platform
// and download each asset digest and related models
let index = 0;
let length = pogo.platforms.length;
for (let platform of pogo.platforms) {
fse.ensureDirSync(CFG.DUMP_ASSET_PATH + platform.name);
pogo.getAssetDigest(platform).then((asset) => {
fs.writeFileSync(CFG.DUMP_ASSET_PATH + platform.name + "/asset_digest", asset.toBuffer());
if (++index >= length) resolve();
});
};
});
}
export function downloadAssets() {
return new Promise((resolve, reject) => {
pogo.getGameMaster().then((master) => {
fs.writeFileSync(CFG.DUMP_ASSET_PATH + "game_master", master.toBuffer());
this.downloadModels().then(() => {
resolve();
});
});
});
}
export function downloadModels() {
let limit = pogo.platforms.length;
return new Promise((resolve, reject) => {
const dump = (index) => {
let platform = pogo.platforms[index];
let name = platform.name;
let caps = capitalize(name);
caps = name === "ios" ? "iOS" : caps;
pogo.setPlatform(name);
this.print(`Preparing to dump ${caps} assets..`, 36);
this.dumpPkmnModels(CFG.DUMP_ASSET_PATH + name + "/", () => {
this.print(`Dumped ${CFG.MAX_POKEMON_NATIONAL_ID} ${caps} assets successfully!`);
if (++index >= limit) {
this.print("Dumped all assets successfully!");
resolve();
return void 0;
}
dump(index);
});
};
dump(0);
});
}
export function dumpPkmnModels(path, resolve) {
let limit = CFG.MAX_POKEMON_NATIONAL_ID;
const dump = (index) => {
let ids = [];
if (++index <= limit) ids.push(index);
if (++index <= limit) ids.push(index);
if (++index <= limit) ids.push(index);
pogo.getAssetByPokemonId(ids).then((downloads) => {
downloads.map((item) => {
this.print(`Dumping model ${item.name}..`, 35);
try {
fs.writeFileSync(path + item.name, item.body);
}
catch (e) {
this.print(`Error while dumping model ${item.name}:` + e, 31);
}
});
if (index >= limit) {
//this.print(`Dumped ${limit} assets successfully!`);
resolve();
return void 0;
}
setTimeout(() => dump(index), 1e3);
});
};
dump(0);
}

View File

@ -1,82 +0,0 @@
import CFG from "../cfg";
/**
* @param {Object} cls
* @param {Object} prot
* @export
*/
export function inherit(cls, prot) {
let key = null;
for (key in prot) {
if (prot[key] instanceof Function) {
cls.prototype[key] = prot[key];
}
};
}
/**
* http://stackoverflow.com/a/7616484/3367904
* @param {String} str
* @return {String}
*/
export function getHashCodeFrom(str) {
var hash = 0, i, chr, len;
if (str.length === 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
/**
* @return {Number}
*/
export function randomRequestId() {
return (
1e18 - Math.floor(Math.random() * 1e18)
);
}
/**
* @param {String} key
* @return {String}
*/
export function _toCC(key) {
key = key.toLowerCase();
let res = key[0].toUpperCase() + key.substring(1, key.length).replace(/_\s*([a-z])/g, function(d, e) {
return e.toUpperCase();
});
return (res);
}
/**
* @param {Number} index
* @return {String}
*/
export function idToPkmnBundleName(index) {
return (
"pm" + (index >= 10 ? index >= 100 ? "0" : "00" : "000") + index
);
}
/**
* @param {String} str
* @return {String}
*/
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))
);
}