- Global shared print method
- API hearbeat and reconnecting feature
- Serialize avatar
- Basic player authentication
- New packet structure for classes
- Safer url routing
This commit is contained in:
Felix 2016-08-27 21:07:40 +02:00
parent c66efe50b4
commit dbde45fe73
22 changed files with 373 additions and 94 deletions

View File

@ -2,6 +2,7 @@ import fs from "fs";
import url from "url";
import prompt from "prompt";
import print from "./print";
import CFG from "../cfg";
prompt.start({
@ -27,7 +28,7 @@ export function processApiCall(req, res, route) {
try {
json = JSON.parse(raw);
} catch (e) {
this.print(e, 31);
print(e, 31);
this.answerApiCall(res, "");
return void 0;
}
@ -44,7 +45,7 @@ export function processApiCall(req, res, route) {
this.answerApiCall(res, JSON.stringify(result));
}
else {
this.print(`${hoster} isnt logged in! Kicking..`, 31);
print(`${hoster} isnt logged in! Kicking..`, 31);
}
}
}
@ -68,11 +69,11 @@ export function grantApiAccess(req, res, route) {
if (result.grant === "y" || result.grant === "yes") {
save.allowedApiHosts.push(hoster);
fs.writeFileSync(".save", JSON.stringify(save), "utf8");
this.print(`Successfully added ${hoster} to allowed API hosts!`);
print(`Successfully added ${hoster} to allowed API hosts!`);
this.processApiCall(req, res, route);
}
else {
this.print(`Denied API access for ${hoster}`, 31);
print(`Denied API access for ${hoster}`, 31);
this.answerApiCall(res, "");
}
});
@ -104,9 +105,9 @@ export function api_login(data) {
) {
success = true;
if (!this.apiClients[data.host]) {
this.print(`API access for ${data.host} granted!`);
print(`API access for ${data.host} granted!`);
}
this.print(`${data.host} logged in!`, 36);
print(`${data.host} logged in!`, 36);
this.apiClients[data.host] = {
timestamp: +new Date()
};
@ -116,9 +117,15 @@ export function api_login(data) {
});
}
export function api_heartBeat() {
return ({
timestamp: +new Date()
});
}
export function api_getConnectedPlayers() {
return ({
connected_players: this.world.players.length
connected_players: this.world.connectedPlayers
});
}
@ -131,7 +138,7 @@ export function api_getServerVersion() {
export function api_spawnPkmnToPlayer(data) {
let name = String(data.player);
let pkmn = String(data.pkmn).toUpperCase();
this.print(`Spawned 1x ${pkmn}'s to ${name}!`);
print(`Spawned 1x ${pkmn}'s to ${name}!`);
return ({
success: true
});

View File

@ -1,3 +1,4 @@
import print from "./print";
import CFG from "../cfg";
export function startCycle() {
@ -61,12 +62,12 @@ export function playerTimeoutTick() {
let players = this.world.players;
let ii = 0;
let length = players.length;
let length = this.world.connectedPlayers;
for (; ii < length; ++ii) {
player = players[ii];
if (this.time - player.timeout >= maxTimeout) {
this.print(`${player.remoteAddress} timed out`, 34);
print(`${player.remoteAddress} timed out`, 34);
this.savePlayer(player);
this.removePlayer(player);
}

View File

@ -1,4 +1,6 @@
import fs from "fs";
import print from "../print";
import CFG from "../../cfg";
export function createTableIfNotExists(name) {
@ -30,7 +32,7 @@ export function createTables() {
export function createTable(name) {
this.print(`Creating table ${name}`, 36);
print(`Creating table ${name}`, 36);
let query = `
CREATE TABLE IF NOT EXISTS ${name} (

View File

@ -1,5 +1,6 @@
import mysql from "mysql";
import print from "../print";
import CFG from "../../cfg";
export function setupDatabaseConnection() {
@ -15,20 +16,20 @@ export function setupDatabaseConnection() {
return new Promise((resolve) => {
connection.connect((error) => {
if (error) {
this.print("MySQL " + error, 31);
print("MySQL " + error, 31);
this.retry("Retrying again in ", () => this.setupDatabaseConnection().then(resolve), 5);
return void 0;
}
this.db = 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`);
print(`\x1b[36;1mMySQL\x1b[0m\x1b[32;1m connection established\x1b[0m`);
resolve();
});
});
});
connection.on("error", (error) => {
this.print("MySQL " + error, 31);
print("MySQL " + error, 31);
this.retry("Trying to reconnect in ", () => this.setupDatabaseConnection().then(resolve), 5);
});
});

View File

@ -1,6 +1,7 @@
import fse from "fs-extra";
import POGOProtos from "pokemongo-protobuf";
import print from "./print";
import CFG from "../cfg";
/**
@ -69,7 +70,7 @@ export function dumpTraffic(req, res) {
let decoded = JSON.stringify(out, null, 2);
fse.outputFileSync(CFG.DEBUG_DUMP_PATH + Date.now(), decoded);
} catch (e) {
this.print("Dump traffic: " + e, 31);
print("Dump traffic: " + e, 31);
}
}

View File

@ -1,5 +1,6 @@
import http from "http";
import print from "./print";
import CFG from "../cfg";
/**
@ -8,7 +9,7 @@ import CFG from "../cfg";
export function createHTTPServer() {
let server = http.createServer((req, res) => {
if (this.world.isFull()) {
this.print(`Server is full! Refused ${req.headers.host}`, 31);
print(`Server is full! Refused ${req.headers.host}`, 31);
return void 0;
}
let chunks = [];
@ -27,10 +28,10 @@ export function createHTTPServer() {
export function shutdown() {
this.socket.close(() => {
this.print("Closed http server!", 33);
print("Closed http server!", 33);
this.closeConnection(() => {
this.print("Closed database connection!", 33);
this.print("Server shutdown!", 31);
print("Closed database connection!", 33);
print("Server shutdown!", 31);
setTimeout(() => process.exit(1), 2e3);
});
});

View File

@ -7,6 +7,7 @@ import {
_toCC
} from "./utils";
import print from "./print";
import CFG from "../cfg";
import World from "./models/World";
@ -59,7 +60,7 @@ export default class GameServer {
if (CFG.GREET) this.greet();
this.print(`Booting Server v${require("../package.json").version}-dev`, 33);
print(`Booting Server v${require("../package.json").version}-dev`, 33);
this.world = new World(this);
@ -67,16 +68,6 @@ export default class GameServer {
}
/**
* @param {String} msg
* @param {Number} color
* @param {Boolean} nl
*/
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 {Object} obj
* @return {Boolean}
@ -96,7 +87,7 @@ export default class GameServer {
retry(msg, fn, timer) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
this.print(`${msg}${timer}s`, 33, true);
print(`${msg}${timer}s`, 33, true);
if (timer >= 1) setTimeout(() => this.retry(msg, fn, --timer), 1e3);
else {
process.stdout.write("\n");
@ -124,7 +115,7 @@ export default class GameServer {
try {
return POGOProtos.parseWithUnknown(buffer, schema);
} catch (e) {
this.print(e, 31);
print(e, 31);
}
}

View File

@ -120,4 +120,18 @@ export default class Avatar {
}
}
serialize() {
return ({
skin: this.skin,
hair: this.hair,
shirt: this.shirt,
pants: this.pants,
hat: this.hat,
shoes: this.shoes,
eyes: this.eyes,
gender: this.gender,
backpack: this.backpack
});
}
}

View File

@ -51,7 +51,7 @@ export default class CandyBag {
/**
* @return {String}
*/
serializeCandies() {
serialize() {
let str = "";
let candies = this.candies;

View File

@ -0,0 +1,47 @@
import Candy from "./Candy";
/**
* @class Tutorial
*/
export default class Tutorial {
/** @constructor */
constructor() {
this.states = [];
this.LEGAL_SCREEN = 0;
this.AVATAR_SELECTION = 1;
this.ACCOUNT_CREATION = 2;
this.POKEMON_CAPTURE = 3;
this.NAME_SELECTION = 4;
this.POKEMON_BERRY = 5;
this.USE_ITEM = 6;
this.FIRST_TIME_EXPERIENCE_COMPLETE = 7;
this.POKESTOP_TUTORIAL = 8;
this.GYM_TUTORIAL = 9;
}
passLegalScreen() {
}
passAvatarSelection() {
}
passAccountCreation() {
}
/**
* @return {Array}
*/
serialize() {
return (
this.states
);
}
}

View File

@ -1,5 +1,14 @@
import Avatar from "./Avatar";
import MapObject from "../World/MapObject";
import POGOProtos from "pokemongo-protobuf";
import jwtDecode from "jwt-decode";
import print from "../../print";
import CFG from "../../../cfg";
import * as _packets from "./packets";
import { inherit } from "../../utils";
import { GAME_MASTER } from "../../master";
@ -16,10 +25,30 @@ export default class Player extends MapObject {
super(null);
this.request = obj.request;
this.response = obj.response;
this.world = obj.world;
this._team = 0;
this.username = "unknown";
this._email = null;
this.email_verified = false;
this.isPTCAccount = false;
this.isGoogleAccount = false;
this.hasSignature = false;
this.authenticated = false;
this.request = null;
this.response = null;
this.remoteAddress = null;
this.maxPkmnStorage = 250;
this.maxItemStorage = 350;
this.authenticated = 0;
/*
this.bag = new Bag(this);
this.info = new Info(this);
@ -28,6 +57,96 @@ export default class Player extends MapObject {
this.pokedex = new Pokedex(this);
this.tutorial = new Tutorial(this);
*/
this.refreshSocket(obj.request, obj.response);
}
}
get team() {
return (this._team);
}
set team(value) {
this.team = value;
}
get email() {
return (this._email);
}
set email(value) {
this.email = value;
this.username = this.email;
}
/**
* @param {Buffer} buffer
*/
sendResponse(buffer) {
this.response.end(buffer);
}
/**
* @param {Request} req
* @param {Response} res
*/
refreshSocket(req, res) {
this.request = req;
this.response = res;
}
authenticate() {
let request = POGOProtos.parseWithUnknown(this.request.body, "POGOProtos.Networking.Envelopes.RequestEnvelope")
let msg = this.GetAuthTicket(request.request_id);
let token = request.auth_info;
if (!token || !token.provider) {
print("Invalid authentication token! Kicking..", 31);
this.world.removePlayer(this);
return void 0;
}
if (token.provider === "google") {
if (token.token !== null) {
let decoded = jwtDecode(token.token.contents);
this.email = decoded.email;
this.email_verified = decoded.email_verified;
this.isGoogleAccount = true;
print(`${this.email} connected!`, 36);
}
else {
print("Invalid authentication token! Kicking..", 31);
this.world.removePlayer(this);
return void 0;
}
}
else {
print("Invalid provider! Kicking..", 31);
this.world.removePlayer(this);
return void 0;
}
this.authenticated = true;
this.sendResponse(msg);
}
/**
* @param {String} type
* @param {Object} msg
*/
getPacket(type, msg) {
return new Promise((resolve) => {
switch (type) {
case "GET_PLAYER":
resolve(this.GetPlayer(msg));
break;
};
});
}
}
inherit(Player, _packets);

View File

@ -0,0 +1,20 @@
import POGOProtos from "pokemongo-protobuf";
export default function GetAuthTicket(id) {
let buffer = ({
status_code: 53,
request_id: id,
api_url: "pgorelease.nianticlabs.com/custom",
auth_ticket: {
start: new Buffer(""),
expire_timestamp_ms: 9999999999999,
end: new Buffer("")
}
});
return (
POGOProtos.serialize(buffer, "POGOProtos.Networking.Envelopes.ResponseEnvelope")
);
}

View File

@ -1,6 +1,6 @@
import POGOProtos from "pokemongo-protobuf";
export function GetInventory() {
export default function GetInventory() {
let stats = this.GetInventoryPlayer();
let items = this.GetInventoryItems();

View File

@ -1,7 +1,25 @@
import POGOProtos from "pokemongo-protobuf";
export function GetPlayer() {
/**
* @param {Object} msg
*/
export default function GetPlayer(msg) {
return (POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetPlayerResponse"));
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.currencies.serialize()
}
return (POGOProtos.serialize({ success: true, player_data: buffer }, "POGOProtos.Networking.Responses.GetPlayerResponse"));
}

View File

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

View File

@ -0,0 +1,4 @@
export GetPlayer from "./GetPlayer";
export GetInventory from "./GetInventory";
export GetAuthTicket from "./GetAuthTicket";
export GetPlayerProfile from "./GetPlayerProfile";

View File

@ -18,12 +18,16 @@ export default class World {
}
get connectedPlayers() {
return (this.players.length);
}
/**
* @return {Boolean}
*/
isFull() {
return (
this.players.length >= CFG.MAX_CONNECTIONS
this.connectedPlayers >= CFG.MAX_CONNECTIONS
);
}
@ -40,27 +44,25 @@ export default class World {
return (player);
}
else {
this.addPlayer(req, res);
player = this.addPlayer(req, res);
return (player);
}
}
/**
* @param {Object} client
* @param {Request} req
* @return {Boolean}
*/
playerAlreadyConnected(client) {
let players = this.players;
playerAlreadyConnected(req) {
let ii = 0;
let length = players.length;
let length = this.connectedPlayers;
let remoteAddress = client.headers.host;
let remoteAddress = req.headers.host;
for (; ii < length; ++ii) {
if (players[ii].remoteAddress === remoteAddress) {
if (this.players[ii].remoteAddress === remoteAddress) {
return (true);
}
};
@ -77,7 +79,7 @@ export default class World {
let players = this.players;
let ii = 0;
let length = players.length;
let length = this.connectedPlayers;
for (; ii < length; ++ii) {
if (players[ii].remoteAddress === ip) {
@ -92,23 +94,29 @@ export default class World {
/**
* @param {Request} req
* @param {Response} res
* @return {Player}
*/
addPlayer(req, res) {
let player = new Player({
world: this,
request: req,
response: res
});
player.remoteAddress = req.headers.host;
this.players.push(player);
return (player);
}
/**
* @param {Player} player
*/
removePlayer(player) {
console.log(player);
console.log("Remove:", player.email);
}
spawnFort() {
@ -123,4 +131,18 @@ export default class World {
}
/**
* @param {String} type
* @param {Object} msg
*/
getPacket(type, msg) {
return new Promise((resolve) => {
switch (type) {
case "CHECK_CHALLENGE":
console.log(type, msg);
break;
};
});
}
}

11
src/print.js Normal file
View File

@ -0,0 +1,11 @@
import CFG from "../cfg";
/**
* @param {String} msg
* @param {Number} color
* @param {Boolean} nl
*/
export default 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" : ""}`);
}

View File

@ -1,5 +1,6 @@
import fs from "fs";
import print from "./print";
import CFG from "../cfg";
const helpMessage = fs.readFileSync(".help", "utf8");
@ -10,7 +11,7 @@ export function processCommand(cmd, data) {
// How many active connections there are
case "/players":
var length = players.length;
this.print(`${length}:${CFG.MAX_CONNECTIONS} connected players!`, 33);
print(`${length}:${CFG.MAX_CONNECTIONS} connected players!`, 33);
break;
// Exit the server
case "/exit":
@ -23,7 +24,7 @@ export function processCommand(cmd, data) {
var length = players.length;
this.removeAllPlayers();
var result = length - players.length;
this.print(`Removed ${result} player${result === 1 ? "": "s"}!`);
print(`Removed ${result} player${result === 1 ? "": "s"}!`);
break;
case "/clear":
process.stdout.write("\x1Bc");
@ -37,7 +38,7 @@ export function processCommand(cmd, data) {
case "/save":
this.saveAllPlayers();
var length = players.length;
this.print(`Saved ${length} player${length === 1 ? "": "s"} into database!`);
print(`Saved ${length} player${length === 1 ? "": "s"} into database!`);
break;
case "/spawn":
this.spawnPkmnAtPlayer(data[1], data[2], data[3] || 1);
@ -46,7 +47,7 @@ export function processCommand(cmd, data) {
eval(fs.readFileSync("update.js", "utf8"));
break;
default:
this.print(`${cmd} is not a valid command!`, 31);
print(`${cmd} is not a valid command!`, 31);
break;
};
};
@ -62,15 +63,15 @@ export function stdinInput(data) {
export function uncaughtException(excp) {
switch (excp.errno) {
case "EADDRINUSE":
this.print(`Port ${CFG.PORT} is already in use!`, 31);
print(`Port ${CFG.PORT} is already in use!`, 31);
break;
case "EACCES":
this.print("No root privileges!", 31);
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);
print("The server has crashed!", 31);
};

View File

@ -3,6 +3,7 @@ import url from "url";
import pcrypt from "pcrypt";
import POGOProtos from "pokemongo-protobuf";
import print from "./print";
import CFG from "../cfg";
/**
@ -36,16 +37,6 @@ export function routeRequest(req, res) {
}
/**
* @param {Request} req
* @param {Response} res
* @param {Array} route
*/
export function processRpcRequest(req, res, route) {
let player = this.world.getPlayerByRequest(req, res);
if (route[2] === "rpc") this.onRequest(player, req);
}
/**
* @param {Request} req
* @param {Response} res
@ -62,16 +53,29 @@ export function processModelRequest(req, res, route) {
let folder = player.isAndroid ? "android/" : "ios/";
fs.readFile("data/" + folder + name, (error, data) => {
if (error) {
this.print(`Error file resolving model ${name}:` + error, 31);
print(`Error file resolving model ${name}:` + error, 31);
return void 0;
}
this.print(`Sent ${name} to ${player.email}`, 36);
print(`Sent ${name} to ${player.email}`, 36);
res.end(data);
});
}
}
/**
* @param {Request} req
* @param {Response} res
* @param {Array} route
*/
export function processRpcRequest(req, res, route) {
let player = this.world.getPlayerByRequest(req, res);
if (route[2] === "rpc") {
player.refreshSocket(req, res);
this.onRequest(player, req);
}
}
/**
* @param {Player} player
* @param {Request} req
@ -89,12 +93,12 @@ export function onRequest(player, req) {
}
if (!player.authenticated) {
player.sendResponse(this.authenticatePlayer(player));
player.authenticate();
return void 0;
}
if (!request.requests.length) {
this.print("Received invalid request!", 31);
print("Received invalid request!", 31);
return void 0;
}
@ -132,7 +136,7 @@ export function envelopResponse(status, returns, req, player, auth) {
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);
print(`${player.email} is playing with an ${player.isIOS ? "Apple" : "Android"} device!`, 36);
}
}

View File

@ -1,5 +1,6 @@
import POGOProtos from "pokemongo-protobuf";
import print from "./print";
import CFG from "../cfg";
import {
@ -8,16 +9,17 @@ import {
} from "./utils";
/**
* @param {Request} req
* @param {Request} req
* @param {String} type
* @return {Buffer}
*/
export function parseMessage(req) {
let proto = `POGOProtos.Networking.Requests.Messages.${cc}Message`;
export function parseMessage(req, type) {
let proto = `POGOProtos.Networking.Requests.Messages.${type}Message`;
if (req.request_message) {
try {
return (this.parseProtobuf(req.request_message, proto));
} catch (e) {
this.print(`Failed to parse ${cc}: ${e}`, 31);
print(`Failed to parse ${type}: ${e}`, 31);
}
}
return void 0;
@ -33,18 +35,30 @@ export function processResponse(player, req) {
let buffer = null;
let cc = _toCC(req.request_type);
let msg = this.parseMessage(req);
let msg = this.parseMessage(req, cc);
return new Promise((resolve) => {
try {
switch (req.request_type) {
case "GET_PLAYER":
player.getPacket("GET_PLAYER", msg).then((result) => {
resolve(result);
});
return void 0;
break;
case "CHECK_CHALLENGE":
player.world.getPacket("CHECK_CHALLENGE", msg).then((result) => {
resolve(result);
});
return void 0;
break;
default:
this.print(`Unknown request: ${req.request_type}`, 31);
print(`Unknown request: ${req.request_type}`, 31);
break;
};
} catch (e) {
this.print(`Response error: ${e}`, 31);
print(`Response error: ${e}`, 31);
};
resolve(buffer);

View File

@ -3,6 +3,7 @@ import fse from "fs-extra";
import pogo from "pogo-asset-downloader";
import POGOProtos from "pokemongo-protobuf";
import print from "./print";
import CFG from "../cfg";
import * as master from "./master";
@ -19,7 +20,7 @@ export function setup() {
let save = JSON.parse(fs.readFileSync(".save", "utf8"));
if (save.isFirstRun) {
this.print("Required assets are missing! Preparing dump session..", 33);
print("Required assets are missing! Preparing dump session..", 33);
setTimeout(() => {
this.onFirstRun(() => {
save.isFirstRun = false;
@ -33,7 +34,7 @@ export function setup() {
// make sure all assets got loaded properly
this.validateAssets().then(() => {
this.print(`Downloaded assets are valid! Proceeding..`);
print(`Downloaded assets are valid! Proceeding..`);
master.GAME_MASTER = this.parseGameMaster();
@ -41,18 +42,18 @@ export function setup() {
this.setupDatabaseConnection().then(() => {
if (CFG.PORT < 1) {
this.print("Invalid port!", 31);
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);
print(`Server listening at ${localIPv4}:${CFG.PORT}`, 33);
});
}).catch((e) => {
//fse.removeSync(CFG.DUMP_ASSET_PATH);
this.print("Error: " + e + " was not found!", 31);
print("Error: " + e + " was not found!", 31);
});
}
@ -131,7 +132,7 @@ export function parseGameMaster() {
master = this.parseProtobuf(data, "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
let Master = new GameMaster(master);
} catch (e) {
this.print(e, 31);
print(e, 31);
}
return (master);
}
@ -147,7 +148,7 @@ export function onFirstRun(resolve) {
this.downloadAssets().then(resolve);
});
}).catch((e) => {
this.print(e, 31);
print(e, 31);
});
}
@ -189,11 +190,11 @@ export function downloadModels() {
let caps = capitalize(name);
caps = name === "ios" ? "iOS" : caps;
pogo.setPlatform(name);
this.print(`Preparing to dump ${caps} assets..`, 36);
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!`);
print(`Dumped ${CFG.MAX_POKEMON_NATIONAL_ID} ${caps} assets successfully!`);
if (++index >= limit) {
this.print("Dumped all assets successfully!");
print("Dumped all assets successfully!");
resolve();
return void 0;
}
@ -216,16 +217,16 @@ export function dumpPkmnModels(path, resolve) {
if (++index <= limit) ids.push(index);
pogo.getAssetByPokemonId(ids).then((downloads) => {
downloads.map((item) => {
this.print(`Dumping model ${item.name}..`, 35);
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);
print(`Error while dumping model ${item.name}:` + e, 31);
}
});
if (index >= limit) {
//this.print(`Dumped ${limit} assets successfully!`);
//print(`Dumped ${limit} assets successfully!`);
resolve();
return void 0;
}