diff --git a/src/enum.js b/src/enum.js index b79eca0..6158d92 100644 --- a/src/enum.js +++ b/src/enum.js @@ -1,7 +1,9 @@ import proto from "node-pogo-protos"; export default { + TEAM: proto.Enums.TeamColor, ITEMS: proto.Inventory.Item.ItemId, + GENDER: proto.Enums.Gender, getItemNameById: (emu, id) => { id <<= 0; for (let key in emu) { diff --git a/src/index.js b/src/index.js index 167352f..5819001 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import fs from "fs"; import os from "os"; import request from "request"; +import readline from "readline"; import POGOProtos from "pokemongo-protobuf"; import { @@ -44,6 +45,8 @@ export default class GameServer { this.db = null; + this.repository = null; + this.apiClients = {}; this.socket = null; @@ -62,6 +65,7 @@ export default class GameServer { this.getLatestVersion().then((latest) => { let current = require("../package.json").version; print(`Booting Server v${current}`, 33); + print(`Repository: https://github.com/${this.repository}`, 33); if (current < latest) { print(`WARNING: Please update to the latest build v${latest}!`, 33); } @@ -81,6 +85,7 @@ export default class GameServer { url = url.replace("git://", ""); url = url.replace(".git", ""); url = url.replace("github.com/", ""); + this.repository = url; url = `${base}/${url}/${branch}/package.json`; resolve(url); }); @@ -190,7 +195,13 @@ inherit(GameServer, _mysql_create); const server = new GameServer(); - process.openStdin().addListener("data", (data) => { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false + }); + + rl.on("line", (data) => { server.stdinInput(data); }); diff --git a/src/models/Player/Avatar/index.js b/src/models/Player/Avatar/index.js index 3fb1297..a0e8094 100644 --- a/src/models/Player/Avatar/index.js +++ b/src/models/Player/Avatar/index.js @@ -13,7 +13,7 @@ export default class Avatar { this._hat = 0; this._shoes = 0; this._eyes = 0; - this._gender = 0; + this._gender = "MALE"; this._backpack = 0; } @@ -105,7 +105,7 @@ export default class Avatar { return (this._gender); } set gender(value) { - if (this.between(value, 0, 1)) { + if (value === "MALE" || value === "FEMALE") { this._gender = value; } } @@ -129,7 +129,7 @@ export default class Avatar { hat: this.hat, shoes: this.shoes, eyes: this.eyes, - gender: this.gender, + gender: this.gender ? "FEMALE" : "MALE", backpack: this.backpack }); } diff --git a/src/models/Player/Currency/index.js b/src/models/Player/Currency/index.js index 5530123..9dc6f7d 100644 --- a/src/models/Player/Currency/index.js +++ b/src/models/Player/Currency/index.js @@ -7,7 +7,7 @@ export default class Currency { constructor() { this.currencies = { - "POKECOINS": 0, + "POKECOIN": 0, "STARDUST": 0 }; diff --git a/src/models/Player/Info/index.js b/src/models/Player/Info/index.js index 2af8af2..374a81c 100644 --- a/src/models/Player/Info/index.js +++ b/src/models/Player/Info/index.js @@ -1,3 +1,7 @@ +import { GAME_MASTER } from "../../../shared"; + +import print from "../../../print"; + /** * @class Info */ @@ -6,13 +10,15 @@ export default class Info { /** @constructor */ constructor() { - this.lvl = 0; + this.lvl = 1; - this.team = 0; + this.team = "NEUTRAL"; - this.exp = 0; - this.prevLvlExp = 0; - this.nextLvlExp = 0; + this.exp = this.getLevelExp(this.lvl); + this.prevLvlExp = this.getLevelExp(this.lvl); + this.nextLvlExp = this.getLevelExp(this.lvl + 1); + + this.levelReward = false; this.kmWalked = 0; this.pkmnEncountered = 0; @@ -35,13 +41,13 @@ export default class Info { getLevelSettings() { return ( - this.owner.gameMaster("PLAYER_LEVEL_SETTINGS") + GAME_MASTER.settings.PLAYER_LEVEL_SETTINGS.player_level ); } getMaximumLevel() { return ( - Object.keys(this.getLevelSettings().player_level).length + this.getLevelSettings().required_experience.length ); } @@ -55,29 +61,45 @@ export default class Info { return (1); } + getLevelExp(lvl) { + return ( + this.getLevelSettings().required_experience[lvl - 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; + if (!this.maxLevelReached()) { + let currentLevelExp = this.getLevelExp(this.lvl); + let nextLevelExp = this.getLevelExp(this.lvl + 1); + let leftExp = nextLevelExp - this.exp; + this.levelReward = false; + if (this.exp + exp >= nextLevelExp) { + this.lvl += 1; + this.prevLvlExp = nextLevelExp; + this.nextLvlExp = this.getLevelExp(this.lvl + 1); + this.exp += leftExp + 1; + this.levelReward = true; + this.upgradeExp(exp - leftExp); + } + else { + this.exp += exp; + } } } + maxLevelReached() { + return ( + this.lvl + 1 >= this.getMaximumLevel() + ); + } + serialize() { return ({ level: this.lvl, experience: this.exp, - prev_level_xp: this.prevLvlExp, next_level_xp: this.nextLvlExp, km_walked: this.kmWalked, pokemons_encountered: this.pkmnEncountered, diff --git a/src/models/Player/index.js b/src/models/Player/index.js index e30b0e6..f583993 100644 --- a/src/models/Player/index.js +++ b/src/models/Player/index.js @@ -119,6 +119,15 @@ export default class Player extends MapObject { getPacket(type, msg) { return new Promise((resolve) => { switch (type) { + case "LEVEL_UP_REWARDS": + resolve(this.LevelUpRewards(msg)); + break; + case "GET_PLAYER_PROFILE": + resolve(this.GetPlayerProfile(msg)); + break; + case "SET_AVATAR": + resolve(this.SetAvatar(msg)); + break; case "GET_PLAYER": resolve(this.GetPlayer(msg)); break; @@ -138,6 +147,26 @@ export default class Player extends MapObject { }); } + /** + * @return {Object} + */ + getPlayerData() { + return ({ + creation_timestamp_ms: +new Date(), + username: this.username, + team: this.info.team, + tutorial_state: this.tutorial.serialize(), + avatar: this.avatar.serialize(), + max_pokemon_storage: 250, + max_item_storage: 350, + daily_bonus: {}, + equipped_badge: {}, + contact_settings: this.contact.serialize(), + currencies: this.currency.serialize(), + remaining_codename_claims: 0 + }); + } + } inherit(Player, _packets); \ No newline at end of file diff --git a/src/models/Player/packets/GetPlayer.js b/src/models/Player/packets/GetPlayer.js index 256c946..ec1d408 100644 --- a/src/models/Player/packets/GetPlayer.js +++ b/src/models/Player/packets/GetPlayer.js @@ -1,5 +1,7 @@ import POGOProtos from "pokemongo-protobuf"; +import ENUM from "../../../enum"; + /** * @param {Object} msg * @return {Buffer} @@ -7,22 +9,12 @@ import POGOProtos from "pokemongo-protobuf"; export default function GetPlayer(msg) { let buffer = { - creation_timestamp_ms: new Date().getTime(), - username: this.username, - team: this.team, - tutorial_state: this.tutorial.serialize(), - avatar: this.avatar.serialize(), - max_pokemon_storage: this.maxPkmnStorage, - max_item_storage: this.maxItemStorage, - daily_bonus: { - next_defender_bonus_collect_timestamp_ms: +new Date() - }, - contact_settings: this.contact.serialize(), - currencies: this.currency.serialize() + success: true, + player_data: this.getPlayerData() }; return ( - POGOProtos.serialize({ success: true, player_data: buffer }, "POGOProtos.Networking.Responses.GetPlayerResponse") + POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerResponse") ); } \ No newline at end of file diff --git a/src/models/Player/packets/GetPlayerProfile.js b/src/models/Player/packets/GetPlayerProfile.js index 51b6576..9b88586 100644 --- a/src/models/Player/packets/GetPlayerProfile.js +++ b/src/models/Player/packets/GetPlayerProfile.js @@ -2,6 +2,18 @@ import POGOProtos from "pokemongo-protobuf"; export default function GetPlayerProfile() { + let buffer = ({ + result: "SUCCESS", + start_time: +new Date(), + badges: [ + { + badge_type: "BADGE_TRAVEL_KM", + end_value: 2674, + current_value: 1337 + } + ] + }); + return ( POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerProfileResponse") ); diff --git a/src/models/Player/packets/LevelUpRewards.js b/src/models/Player/packets/LevelUpRewards.js new file mode 100644 index 0000000..dd6973a --- /dev/null +++ b/src/models/Player/packets/LevelUpRewards.js @@ -0,0 +1,28 @@ +import POGOProtos from "pokemongo-protobuf"; + +/** + * @param {Object} msg + * @return {Buffer} + */ +export default function LevelUpRewards(msg) { + + let buffer = { + result: "SUCCESS", + items_awarded: [ + { + item_id: "ITEM_POKE_BALL", + item_count: 2 + }, + { + item_id: "ITEM_TROY_DISK", + item_count: 2 + } + ], + items_unlocked: [] + }; + + return ( + POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.LevelUpRewardsResponse") + ); + +} \ No newline at end of file diff --git a/src/models/Player/packets/SetAvatar.js b/src/models/Player/packets/SetAvatar.js new file mode 100644 index 0000000..dc1cd04 --- /dev/null +++ b/src/models/Player/packets/SetAvatar.js @@ -0,0 +1,22 @@ +import POGOProtos from "pokemongo-protobuf"; + +/** + * @param {Object} msg + * @return {Buffer} + */ +export default function SetAvatar(msg) { + + for (let key in msg.player_avatar) { + this.avatar[key] = msg.player_avatar[key]; + }; + + let buffer = ({ + status: "SUCCESS", + player_data: this.getPlayerData() + }); + + return ( + POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.SetAvatarResponse") + ); + +} \ No newline at end of file diff --git a/src/models/Player/packets/index.js b/src/models/Player/packets/index.js index a3a9b28..97425b4 100644 --- a/src/models/Player/packets/index.js +++ b/src/models/Player/packets/index.js @@ -1,6 +1,8 @@ +export SetAvatar from "./SetAvatar"; export GetPlayer from "./GetPlayer"; export GetInventory from "./GetInventory"; export GetAuthTicket from "./GetAuthTicket"; +export LevelUpRewards from "./LevelUpRewards"; export GetHatchedEggs from "./GetHatchedEggs"; export GetAssetDigest from "./GetAssetDigest"; export GetPlayerProfile from "./GetPlayerProfile"; diff --git a/src/models/World/Cell/index.js b/src/models/World/Cell/index.js index 47f1188..5278872 100644 --- a/src/models/World/Cell/index.js +++ b/src/models/World/Cell/index.js @@ -59,7 +59,7 @@ export default class Cell extends MapObject { this.processDeletedFort(this.addFort(fort)); }); this.synced = true; - print(`Synced ${this.cellId} with database..`, 33); + //print(`Synced ${this.cellId} with database..`, 33); resolve(this.forts); }); } diff --git a/src/models/World/Fort/Gym/index.js b/src/models/World/Fort/Gym/index.js index 650ca1f..0c499bb 100644 --- a/src/models/World/Fort/Gym/index.js +++ b/src/models/World/Fort/Gym/index.js @@ -7,6 +7,8 @@ import { validName } from "../../../../utils"; +import ENUM from "../../../../enum"; + /** * @class Gym */ @@ -20,7 +22,7 @@ export default class Gym extends Fort { super(obj); - this.team = "RED"; + this.team = 0; this.guardPkmn = 0; this.guardPkmnCp = 0; @@ -43,7 +45,7 @@ export default class Gym extends Fort { latitude: this.latitude, longitude: this.longitude, enabled: this.enabled, - owned_by_team: this.team, + owned_by_team: ENUM.getItemNameById(ENUM.TEAM, this.team), guard_pokemon_id: this.guardPkmn, gym_points: this.gymPoints, active_fort_modifier: [] diff --git a/src/models/World/Fort/index.js b/src/models/World/Fort/index.js index a68ec12..0d719ad 100644 --- a/src/models/World/Fort/index.js +++ b/src/models/World/Fort/index.js @@ -27,6 +27,8 @@ export default class Fort extends MapObject { this.init(obj); + this.uid += this.type[0].toUpperCase(); + } /** diff --git a/src/models/World/packets/FortSearch.js b/src/models/World/packets/FortSearch.js index 90b6cba..4fbc22e 100644 --- a/src/models/World/packets/FortSearch.js +++ b/src/models/World/packets/FortSearch.js @@ -9,6 +9,8 @@ import print from "../../../print"; */ export default function FortSearch(msg) { + let player = msg.player; + return new Promise((resolve) => { this.getFortDataById(msg.fort_id).then((fort) => { if (!fort) return void 0; @@ -19,6 +21,7 @@ export default function FortSearch(msg) { cooldown_complete_timestamp_ms: +new Date() + fort.cooldown, chain_hack_sequence_number: 2 }); + player.info.upgradeExp(fort.experience); resolve( POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.FortSearchResponse") ); diff --git a/src/models/World/packets/GetMapObjects.js b/src/models/World/packets/GetMapObjects.js index 037f177..9d66157 100644 --- a/src/models/World/packets/GetMapObjects.js +++ b/src/models/World/packets/GetMapObjects.js @@ -39,12 +39,12 @@ export default function GetMapObjects(msg) { cell.forts.map((fort) => { let id = fort.cellId + "." + fort.uid; if (ids.indexOf(id) > -1) { - print(`Duplicated!!!! => ${id}`, 31); + print(`Duplicated fort!!!! => ${id}`, 31); } else { ids.push(id); } - print(`Active fort: ${fort.cellId}.${fort.uid}`, 35); + //print(`Active fort: ${fort.cellId}.${fort.uid}`, 35); }); } mapCells.push({ diff --git a/src/modes/index.js b/src/modes/index.js index 569e660..fb29af7 100644 --- a/src/modes/index.js +++ b/src/modes/index.js @@ -14,8 +14,8 @@ export default { pokemon_visible_range: 70.00196078431372, poke_nav_range_meters: 751.0156862745098, encounter_range_meters: 50.25098039215686, - get_map_objects_min_refresh_seconds: 4, - get_map_objects_max_refresh_seconds: 4, + get_map_objects_min_refresh_seconds: 16, + get_map_objects_max_refresh_seconds: 16, get_map_objects_min_distance_meters: 10.007843017578125, google_maps_api_key: CFG.GMAPS_KEY }, diff --git a/src/process.js b/src/process.js index 7fd80db..3a01299 100644 --- a/src/process.js +++ b/src/process.js @@ -43,8 +43,11 @@ export function processCommand(cmd, data) { case "/spawn": this.spawnPkmnAtPlayer(data[1], data[2], data[3] || 1); break; - case "/update": - eval(fs.readFileSync("update.js", "utf8")); + case "/dump": + print("Preparing dump session.."); + this.onFirstRun(() => { + print("Dumped assets successfully!"); + }); break; default: print(`${cmd} is not a valid command!`, 31); @@ -53,11 +56,9 @@ export function processCommand(cmd, data) { }; 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); + if (data.length <= 1) return void 0; + let cmds = data.split(" "); + this.processCommand(cmds[0], cmds.splice(0, 1)); }; export function uncaughtException(excp) { diff --git a/src/response.js b/src/response.js index 0a68407..fd1f991 100644 --- a/src/response.js +++ b/src/response.js @@ -40,10 +40,13 @@ export function processResponse(player, req) { try { switch (req.request_type) { // Player + case "SET_AVATAR": case "GET_PLAYER": case "GET_INVENTORY": case "GET_ASSET_DIGEST": case "GET_HATCHED_EGGS": + case "LEVEL_UP_REWARDS": + case "GET_PLAYER_PROFILE": case "CHECK_AWARDED_BADGES": player.getPacket(req.request_type, msg).then((result) => { print(`Success: ${req.request_type} => ${result.toString().length}`); diff --git a/src/setup.js b/src/setup.js index b63b7cb..a02b262 100644 --- a/src/setup.js +++ b/src/setup.js @@ -11,6 +11,7 @@ import * as shared from "./shared"; import GameMaster from "./models/GameMaster"; import { + _toCC, capitalize, idToPkmnBundleName } from "./utils"; @@ -141,12 +142,13 @@ export function parseGameMaster() { } export function onFirstRun(resolve) { - // make sure to login first! + print(`Attempt to login with ${_toCC(CFG.DOWNLOAD_PROVIDER)}..`, 33); pogo.login({ provider: CFG.DOWNLOAD_PROVIDER, // google or ptc username: CFG.DOWNLOAD_USERNAME, password: CFG.DOWNLOAD_PASSWORD }).then(() => { + print(`Successfully logged in!`); this.downloadAssetDigests().then(() => { this.downloadAssets().then(resolve); });