From 6a983bc8bec2f81063f2b4f40dd4ca0a5820ab34 Mon Sep 17 00:00:00 2001 From: Felix Date: Mon, 12 Sep 2016 15:34:47 +0200 Subject: [PATCH] Update - Basic upgrade pkmn - Basic pokedex - Player consumes fort rewards - Only refresh player position on GET_MAP_OBJECTS req - Fixed pkmn inventory related bugs - Updated to v 0.5.8 --- cfg.js.example | 8 ++- package.json | 2 +- src/db/create.js | 4 +- src/db/get.js | 5 +- src/models/Player/Party/index.js | 3 +- src/models/Player/PokeDex/index.js | 67 ++++++++++++++++++++ src/models/Player/index.js | 68 +++++++++++++++------ src/models/Player/packets/UpgradePokemon.js | 28 +++++++++ src/models/Player/packets/index.js | 1 + src/models/Pokemon/WildPokemon/index.js | 41 ++++++++++++- src/models/Pokemon/action.js | 6 +- src/models/Pokemon/calc.js | 24 ++++---- src/models/Pokemon/index.js | 28 +++++---- src/models/World/Cell/index.js | 1 - src/models/World/packets/Encounter.js | 12 ++-- src/models/World/packets/FortDetails.js | 1 - src/models/World/packets/FortSearch.js | 2 + src/models/World/players.js | 2 +- src/process.js | 9 +-- src/request.js | 4 +- src/response.js | 1 + 21 files changed, 251 insertions(+), 66 deletions(-) create mode 100644 src/models/Player/PokeDex/index.js create mode 100644 src/models/Player/packets/UpgradePokemon.js diff --git a/cfg.js.example b/cfg.js.example index 56f8287..890a781 100644 --- a/cfg.js.example +++ b/cfg.js.example @@ -8,8 +8,11 @@ export default { // show greeting GREET: true, - // allow api calls - ENABLE_API: true, + + // Api things + API_ENABLE: true, + API_USERNAME: "root", + API_PASSWORD: "", // Server settings MAX_CONNECTIONS: 64, @@ -24,6 +27,7 @@ export default { // Timeouts BOOT_TIMEOUT: 1e4, PLAYER_CONNECTION_TIMEOUT: 1e3 * 60 * 30, + CELL_TIMEOUT: 1e3 * 60, MINIMUM_CLIENT_VERSION: "0.35.0", DEFAULT_CONSOLE_COLOR: 32, TRANSFER_ACCOUNTS: false, diff --git a/package.json b/package.json index 3e9219e..bf3fc3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "POGOServer", - "version": "0.5.6", + "version": "0.5.8", "description": "", "repository": { "type": "git", diff --git a/src/db/create.js b/src/db/create.js index f9d18a3..27717a3 100644 --- a/src/db/create.js +++ b/src/db/create.js @@ -6,7 +6,7 @@ import CFG from "../../cfg"; export function createTableIfNotExists(name) { return new Promise((resolve) => { this.db.query(`SHOW TABLES LIKE '${name}';`, (e, rows, fields) => { - if (e) console.log(e); + if (e) print(e, 31); else { // exists if (rows && rows.length) resolve(); @@ -48,7 +48,7 @@ export function createTable(name) { return new Promise((resolve) => { this.db.query(query, (e, rows) => { - if (e) console.log(e); + if (e) print(e, 31); else resolve(); }); }); diff --git a/src/db/get.js b/src/db/get.js index 93fbfd4..df4e019 100644 --- a/src/db/get.js +++ b/src/db/get.js @@ -1,3 +1,4 @@ +import print from "../print"; import CFG from "../../cfg"; /** @@ -8,7 +9,7 @@ import CFG from "../../cfg"; export function getQueryByColumnFromTable(column, value, table) { return new Promise((resolve) => { this.db.query(`SELECT * FROM ${table} WHERE ${column}=?`, [value], (e, rows) => { - if (e) console.log(e); + if (e) print(e, 31); if (rows && rows.length) resolve(rows); else resolve(void 0); }); @@ -23,7 +24,7 @@ export function getQueryByColumnFromTable(column, value, table) { export function deleteQueryByColumnFromTable(column, value, table) { return new Promise((resolve) => { this.db.query(`DELETE FROM ${table} WHERE ${column}=?`, [value], (e, rows) => { - if (e) console.log(e); + if (e) print(e, 31); else resolve(void 0); }); }); diff --git a/src/models/Player/Party/index.js b/src/models/Player/Party/index.js index 3b1bdd8..9f2050d 100644 --- a/src/models/Player/Party/index.js +++ b/src/models/Player/Party/index.js @@ -28,6 +28,7 @@ export default class Party { this.player.world.db.query(query, [this.player.uid], (e, rows) => { if (e) return print(e, 31); rows.map((row) => { + row.isOwned = true; this.addPkmn(row); }); resolve(); @@ -40,7 +41,7 @@ export default class Party { * @return {Pokemon} */ addPkmn(obj) { - if (!obj.owner) obj.owner = this.player; + obj.owner = this.player; let pkmn = new Pokemon(obj); this.party.push(pkmn); return (pkmn); diff --git a/src/models/Player/PokeDex/index.js b/src/models/Player/PokeDex/index.js new file mode 100644 index 0000000..01c7930 --- /dev/null +++ b/src/models/Player/PokeDex/index.js @@ -0,0 +1,67 @@ +import { GAME_MASTER } from "../../../shared"; + +import ENUM from "../../../enum"; + +/** + * @class PokeDex + */ +export default class PokeDex { + + /** + * @param {Player} player + * @constructor + */ + constructor(player) { + + this.player = player; + + this.pkmns = {}; + + } + + /** + * @param {Number} dex + */ + addEntry(dex) { + + } + + /** + * @param {Number} dex + */ + removeEntry(dex) { + + } + + /** + * @return {Array} + */ + serialize() { + let out = []; + for (let key in this.pkmns) { + let pkmn = this.pkmns[key]; + out.push({ + modified_timestamp_ms: +new Date() - 1e3, + inventory_item_data: { + pokedex_entry: { + pokemon_id: key, + times_encountered: 1, + times_captured: 1 + } + } + }); + }; + return (out); + } + + /** + * @param {String} str + */ + parseJSON(str) { + let pkmns = JSON.parse(str); + for (let pkmn in pkmns) { + this.addEntry(pkmn); + }; + } + +} \ No newline at end of file diff --git a/src/models/Player/index.js b/src/models/Player/index.js index 730b366..dc0c483 100644 --- a/src/models/Player/index.js +++ b/src/models/Player/index.js @@ -4,8 +4,9 @@ import Bag from "./Bag"; import Info from "./Info"; import Party from "./Party"; import Avatar from "./Avatar"; -import CandyBag from "./CandyBag"; +import Pokedex from "./Pokedex"; import Contact from "./Contact"; +import CandyBag from "./CandyBag"; import Tutorial from "./Tutorial"; import Currency from "./Currency"; @@ -21,6 +22,8 @@ import { parseSignature } from "../../utils"; +import ENUM from "../../enum"; + import { GAME_MASTER } from "../../shared"; /** @@ -64,17 +67,16 @@ export default class Player extends MapObject { this.currentEncounter = null; this.bag = new Bag(this); - this.candyBag = new CandyBag(this); this.info = new Info(this); this.party = new Party(this); this.avatar = new Avatar(this); + this.pokeDex = new Pokedex(this); this.contact = new Contact(this); + this.candyBag = new CandyBag(this); this.tutorial = new Tutorial(this); this.currency = new Currency(this); - /* - this.pokedex = new Pokedex(this); - */ + this.refreshSocket(obj.request, obj.response); } @@ -94,6 +96,19 @@ export default class Player extends MapObject { this.response.end(buffer); } + /** + * @param {Request} req + * @param {String} type + * @return {Boolean} + */ + requestContains(req, type) { + let requests = req.requests; + for (let request of requests) { + if (request.request_type === type) return (true); + }; + return (false); + } + /** * @param {Request} req * @param {Response} res @@ -105,6 +120,20 @@ export default class Player extends MapObject { this.refreshPosition(); } + refreshPosition() { + let req = this.request; + if ( + req.latitude !== void 0 && + req.longitude !== void 0 + ) { + this.latitude = req.latitude; + this.longitude = req.longitude; + } + if (this.requestContains(req, "GET_MAP_OBJECTS")) { + this.world.triggerSpawnAt(this.latitude, this.longitude); + } + } + getDevicePlatform() { let request = this.request; if (request.unknown6 && request.unknown6[0]) { @@ -137,6 +166,9 @@ export default class Player extends MapObject { resolve(result); }); break; + case "UPGRADE_POKEMON": + resolve(this.UpgradePokemon(msg)); + break; case "GET_PLAYER_PROFILE": resolve(this.GetPlayerProfile(msg)); break; @@ -254,16 +286,17 @@ export default class Player extends MapObject { }); } - refreshPosition() { - let req = this.request; - if ( - req.latitude !== void 0 && - req.longitude !== void 0 - ) { - this.latitude = req.latitude; - this.longitude = req.longitude; - } - this.world.triggerSpawnAt(this.latitude, this.longitude); + /** + * @param {Fort} fort + */ + consumeFortRewards(fort) { + let rewards = fort.rewards; + for (let key in rewards) { + let name = ENUM.getNameById(ENUM.ITEMS, key << 0).replace("ITEM_", "").toLowerCase(); + if (this.bag.hasOwnProperty(name)) { + this.bag[name] += rewards[key] << 0; + } + }; } /** @@ -279,10 +312,11 @@ export default class Player extends MapObject { pkmn.pokeball = ball; return new Promise((resolve) => { pkmn.owner = this; - pkmn.calcStats(); pkmn.insertIntoDatabase().then((insertId) => { + let cp = pkmn.getSeenCp(this); + pkmn.isOwned = false; pkmn = this.party.addPkmn(pkmn); - pkmn.owner = this; + pkmn.cp = cp; pkmn.uid = insertId; pkmn.addCandies(3); print(`${this.username} caught a wild ${pkmn.getPkmnName()}!`); diff --git a/src/models/Player/packets/UpgradePokemon.js b/src/models/Player/packets/UpgradePokemon.js new file mode 100644 index 0000000..1d8ea43 --- /dev/null +++ b/src/models/Player/packets/UpgradePokemon.js @@ -0,0 +1,28 @@ +import POGOProtos from "pokemongo-protobuf"; + +/** + * @param {Object} msg + * @return {Buffer} + */ +export default function UpgradePokemon(msg) { + + let buffer = null; + let pkmn = this.party.getPkmnById(msg.pokemon_id); + + if (pkmn) { + if (pkmn.powerUp()) { + buffer = { result: "SUCCESS" }; + } else { + buffer = { result: "ERROR_INSUFFICIENT_RESOURCES" }; + } + buffer.upgraded_pokemon = pkmn.serialize(); + } + else { + buffer = { result: "ERROR_POKEMON_NOT_FOUND" }; + } + + return ( + POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.UpgradePokemonResponse") + ); + +} \ No newline at end of file diff --git a/src/models/Player/packets/index.js b/src/models/Player/packets/index.js index c374252..7ccd078 100644 --- a/src/models/Player/packets/index.js +++ b/src/models/Player/packets/index.js @@ -3,6 +3,7 @@ export GetPlayer from "./GetPlayer"; export GetInventory from "./GetInventory"; export GetAuthTicket from "./GetAuthTicket"; export ReleasePokemon from "./ReleasePokemon"; +export UpgradePokemon from "./UpgradePokemon"; export LevelUpRewards from "./LevelUpRewards"; export GetHatchedEggs from "./GetHatchedEggs"; export GetAssetDigest from "./GetAssetDigest"; diff --git a/src/models/Pokemon/WildPokemon/index.js b/src/models/Pokemon/WildPokemon/index.js index 2a4f185..d30569c 100644 --- a/src/models/Pokemon/WildPokemon/index.js +++ b/src/models/Pokemon/WildPokemon/index.js @@ -32,6 +32,9 @@ export default class WildPokemon extends Pokemon { // players who already caught this pkmn this.hasCatched = []; + // players who already have seen this pkmn (to store cp) + this.hasSeen = []; + } /** @@ -54,6 +57,42 @@ export default class WildPokemon extends Pokemon { ); } + /** + * @param {Player} player + * @return {Number} + */ + getSeenCp(player) { + for (let item of this.hasSeen) { + if (item.uid === player.uid) return (item.cp); + }; + return (-1); + } + + /** + * @param {Player} player + * @return {Boolean} + */ + seenBy(player) { + if (!this.alreadySeenBy(player)) { + this.calcStats(player); + this.hasSeen.push({ + cp: this.cp, + uid: player.uid + }); + } + } + + /** + * @param {Player} player + * @return {Boolean} + */ + alreadySeenBy(player) { + for (let item of this.hasSeen) { + if (item.uid === player.uid) return (true); + }; + return (false); + } + /** * @return {Boolean} */ @@ -91,7 +130,7 @@ export default class WildPokemon extends Pokemon { spawn_point_id: this.spawnPointId, pokemon_data: { pokemon_id: this.getPkmnId(), - cp: 66, + cp: this.cp, stamina: 10, stamina_max: 10, move_1: "BUG_BITE_FAST", diff --git a/src/models/Pokemon/action.js b/src/models/Pokemon/action.js index f834fe3..b4d6b5f 100644 --- a/src/models/Pokemon/action.js +++ b/src/models/Pokemon/action.js @@ -17,11 +17,11 @@ export function powerUp() { let pkmnTmpl = this.getPkmnTemplate(this.dexNumber); let ownerStardust = this.owner.info.stardust; let ownerPkmnCandies = this.owner.candyBag.getCandy(this.dexNumber); - let requiredCandies = this.candiesToPowerUp(); - print(`${this.getPkmnName()} requires ${requiredCandies} to power up!`); + let requiredCandies = 1; + print(`${this.getPkmnName()} requires ${requiredCandies} candies to power up!`); if (ownerPkmnCandies >= requiredCandies) { this.level += 1; - this.owner.candyBag.removeCandy(this.dexNumber, pkmnTmpl.candy_to_evolve); + this.owner.candyBag.removeCandy(this.dexNumber, requiredCandies); return (true); } return (false); diff --git a/src/models/Pokemon/calc.js b/src/models/Pokemon/calc.js index 09aa0c6..5778513 100644 --- a/src/models/Pokemon/calc.js +++ b/src/models/Pokemon/calc.js @@ -1,6 +1,9 @@ import Settings from "../../modes"; -export function calcStats() { +/** + * @param {Player} owner + */ +export function calcStats(owner) { let pkmnTmpl = this.getPkmnTemplate(this.dexNumber); let stats = pkmnTmpl.stats; @@ -20,7 +23,9 @@ export function calcStats() { this.height = pkmnTmpl.pokedex_height_m + ((Math.random() * pkmnTmpl.height_std_dev) + .1); this.weight = pkmnTmpl.pokedex_weight_kg + ((Math.random() * pkmnTmpl.weight_std_dev) + .1); - this.cp = Math.floor(Math.random() * this.calcCP()) + 16; + if (owner !== null) { + this.cp = Math.floor(Math.random() * this.calcCP(owner)) + 16; + } this.calcMoves(); @@ -39,11 +44,13 @@ export function calcMoves() { } /** + * @param {Player} owner * @return {Number} */ -export function calcCP() { +export function calcCP(owner) { - let ecpm = this.getCPMultipliers()[this.owner.info.level - 1]; + let levelSettings = owner.info.getLevelSettings(); + let ecpm = levelSettings.cp_multiplier[owner.info.level - 1]; let atk = (this.attack + this.ivAttack) * ecpm; let def = (this.defense + this.ivDefense) * ecpm; @@ -55,15 +62,6 @@ export function calcCP() { } -/** - * @return {Array} - */ -export function getCPMultipliers() { - return ( - this.owner.info.getLevelSettings().cp_multiplier - ); -} - /** * @param {Number} lvl * @return {Number} diff --git a/src/models/Pokemon/index.js b/src/models/Pokemon/index.js index 7662756..0fac159 100644 --- a/src/models/Pokemon/index.js +++ b/src/models/Pokemon/index.js @@ -66,6 +66,7 @@ export default class Pokemon extends MapObject { this.pokeball = null; this.isWild = false; + this.isOwned = false; this.spawnPoint = null; @@ -78,7 +79,6 @@ export default class Pokemon extends MapObject { } set level(value) { this._level = parseFloat(value); - this.calcStats(); } /** @@ -102,10 +102,23 @@ export default class Pokemon extends MapObject { else if (key === "move_2") { this.move2 = obj[key]; } + else if (key === "height_m") { + this.height = obj[key]; + } + else if (key === "weight_kg") { + this.weight = obj[key]; + } + else if (key === "individual_attack") { + this.ivAttack = obj[key]; + } + else if (key === "individual_defense") { + this.ivDefense = obj[key]; + } + else if (key === "individual_stamina") { + this.ivStamina = obj[key]; + } }; - if (!obj.isWild) { - this.calcStats(); - } + if (!obj.isWild && !obj.isOwned) this.calcStats(this.owner); } /** @@ -189,13 +202,6 @@ export default class Pokemon extends MapObject { return (pkmnTmpl.candy_to_evolve << 0); } - /** - * @return {Number} - */ - candiesToPowerUp() { - return (1337); - } - /** * @return {Boolean} */ diff --git a/src/models/World/Cell/index.js b/src/models/World/Cell/index.js index 3a98a43..9705ad4 100644 --- a/src/models/World/Cell/index.js +++ b/src/models/World/Cell/index.js @@ -192,7 +192,6 @@ export default class Cell extends MapObject { * @return {Number} */ getFortIndexById(id) { - id = parseInt(id); let index = 0; for (let fort of this.forts) { if (fort.uid === id) return (index); diff --git a/src/models/World/packets/Encounter.js b/src/models/World/packets/Encounter.js index 56e85ab..76a24b0 100644 --- a/src/models/World/packets/Encounter.js +++ b/src/models/World/packets/Encounter.js @@ -5,8 +5,10 @@ import POGOProtos from "pokemongo-protobuf"; */ export default function Encounter(msg) { + let player = msg.player; + // Try to use cached encounter - let encounter = msg.player.currentEncounter; + let encounter = player.currentEncounter; // Dont use cached encounter if ( @@ -26,17 +28,19 @@ export default function Encounter(msg) { // Invalid pkmn if (!encounter) { - msg.player.currentEncounter = null; + player.currentEncounter = null; buffer.status = "ENCOUNTER_NOT_FOUND"; } // Already encountered - else if (encounter.alreadyCatchedBy(msg.player)) { + else if (encounter.alreadyCatchedBy(player)) { buffer.status = "ENCOUNTER_ALREADY_HAPPENED"; } // Encounter success else { - msg.player.currentEncounter = encounter; + player.currentEncounter = encounter; + encounter.seenBy(player); buffer.wild_pokemon = encounter.serializeWild(); + buffer.wild_pokemon.pokemon_data.cp = encounter.getSeenCp(player); } return ( diff --git a/src/models/World/packets/FortDetails.js b/src/models/World/packets/FortDetails.js index 82c6b87..9464eb4 100644 --- a/src/models/World/packets/FortDetails.js +++ b/src/models/World/packets/FortDetails.js @@ -12,7 +12,6 @@ export default function FortDetails(msg) { return new Promise((resolve) => { this.getFortDataById(msg.fort_id).then((fort) => { if (!fort) return void 0; - let ts = +new Date(); let url = fort.image_url; let buffer = { fort_id: msg.fort_id, diff --git a/src/models/World/packets/FortSearch.js b/src/models/World/packets/FortSearch.js index 4fbc22e..9f7867b 100644 --- a/src/models/World/packets/FortSearch.js +++ b/src/models/World/packets/FortSearch.js @@ -14,6 +14,8 @@ export default function FortSearch(msg) { return new Promise((resolve) => { this.getFortDataById(msg.fort_id).then((fort) => { if (!fort) return void 0; + player.consumeFortRewards(fort); + // TODO: disable rewarding when on cooldown let buffer = ({ result: "SUCCESS", items_awarded: fort.serializeRewards(), diff --git a/src/models/World/players.js b/src/models/World/players.js index 3f529a4..c4de65e 100644 --- a/src/models/World/players.js +++ b/src/models/World/players.js @@ -122,5 +122,5 @@ export function addPlayer(req, res) { * @param {Player} player */ export function removePlayer(player) { - console.log("Remove:", player.email); + print(`Removed ${player.email}`, 36); } \ No newline at end of file diff --git a/src/process.js b/src/process.js index e1afb95..9bde330 100644 --- a/src/process.js +++ b/src/process.js @@ -61,8 +61,8 @@ export function stdinInput(data) { this.processCommand(cmds[0], cmds.splice(0, 1)); }; -export function uncaughtException(excp) { - switch (excp.errno) { +export function uncaughtException(e) { + switch (e.errno) { case "EADDRINUSE": print(`Port ${CFG.PORT} is already in use!`, 31); break; @@ -70,8 +70,9 @@ export function uncaughtException(excp) { print("No root privileges!", 31); break; default: - console.log("Unhandled exception occurred: ", excp.code); - console.log(excp.stack); + print("Unhandled exception occurred: ", 31); + print(e, 31); + print(e.stack, 31); break; }; print("The server has crashed!", 31); diff --git a/src/request.js b/src/request.js index 0aa08a1..38be886 100644 --- a/src/request.js +++ b/src/request.js @@ -40,7 +40,7 @@ export function routeRequest(req, res) { } break; default: - console.log(`Unknown request url: https://${host}${req.url}`); + print(`Unknown request url: https://${host}${req.url}`, 31); break; }; @@ -125,7 +125,7 @@ export function onRequest(player) { request.requests.map((request) => { let reqSize = Buffer.byteLength(request.request_message, "utf8"); let resSize = Buffer.byteLength(returns[index], "utf8"); - console.log(`[Packet]: ${request.request_type}`, `${reqSize} => ${resSize}`); + print(`${request.request_type} ${reqSize} => ${resSize}`, 37); index++; }); } diff --git a/src/response.js b/src/response.js index 07940f9..c519348 100644 --- a/src/response.js +++ b/src/response.js @@ -43,6 +43,7 @@ export function processResponse(player, req) { case "GET_PLAYER": case "GET_INVENTORY": case "RELEASE_POKEMON": + case "UPGRADE_POKEMON": case "GET_ASSET_DIGEST": case "NICKNAME_POKEMON": case "GET_HATCHED_EGGS":