- Cell timeouts
- Faster cell map object serializing
- Release pokemons
- Save catched pkmns into db
- Fixed pkmn inventory invisible model bug
- Use uid instead of id everywhere
- Auto calc moves when call init calculations
- Random cp multiplier
- Added wild pkmn flee ability
- Start unique hashes from 1
- Added decapitalize util method
This commit is contained in:
Felix
2016-09-09 19:02:59 +02:00
parent 6df19de530
commit 380f5d6f87
15 changed files with 276 additions and 145 deletions

View File

@@ -39,14 +39,15 @@ export function updateTimers() {
}
export function resetTimers() {
if (this.tick >= 25) {
if (this.tick >= 1e4) {
this.fullTick++;
if (this.fullTick >= 2) {
this.fullTick = 0;
}
this.tick = 0;
// Player timeout tick, not precise
// Timeout ticks, not precise
this.playerTimeoutTick();
this.cellTimeoutTick();
}
this.saveTick++;
// Save interval
@@ -64,15 +65,11 @@ export function resetTimers() {
}
export function playerTimeoutTick() {
let player = null;
let maxTimeout = CFG.PLAYER_CONNECTION_TIMEOUT;
let players = this.world.players;
let ii = 0;
let length = this.world.connectedPlayers;
let player = null;
let players = this.world.players;
for (; ii < length; ++ii) {
player = players[ii];
if (this.time - player.timeout >= maxTimeout) {
@@ -81,5 +78,17 @@ export function playerTimeoutTick() {
this.removePlayer(player);
}
};
}
export function cellTimeoutTick() {
let ii = 0;
let length = this.world.cells.length;
let cell = null;
for (; ii < length; ++ii) {
cell = this.world.cells[ii];
if (cell.expiration - +new Date() <= 0) {
cell.delete();
length--;
}
};
}

View File

@@ -20,29 +20,30 @@ export default class Party {
this.party = [];
this.addPkmn({
dexNumber: 4,
pokeball: "ITEM_POKE_BALL",
favorite: 0
});
this.fetchFromDatabase();
}
fetchFromDatabase() {
let instance = this.player.world.db;
this.player.world.db.query(`SELECT * FROM ${CFG.MYSQL_OWNED_PKMN_TABLE} WHERE owner_id=?`, [this.player.id], (e, rows) => {
if (e) return print(e, 31);
syncWithDatabase() {
let query = `SELECT * FROM ${CFG.MYSQL_OWNED_PKMN_TABLE} WHERE owner_id=?`;
return new Promise((resolve) => {
this.player.world.db.query(query, [this.player.uid], (e, rows) => {
if (e) return print(e, 31);
rows.map((row) => {
this.addPkmn(row);
});
resolve();
});
});
}
/**
* @param {Object} obj
* @return {Pokemon}
*/
addPkmn(obj) {
if (!obj.owner) obj.owner = this.player;
this.party.push(new Pokemon(obj));
let pkmn = new Pokemon(obj);
this.party.push(pkmn);
return (pkmn);
}
/**
@@ -50,8 +51,9 @@ export default class Party {
* @return {Number}
*/
getPkmnIndexById(id) {
id = parseInt(id);
for (let ii = 0; ii < this.party.length; ++ii) {
if (this.party[ii].id === id) return (ii);
if (this.party[ii].uid === id) return (ii);
};
return (-1);
}
@@ -67,12 +69,11 @@ export default class Party {
/**
* @param {Number} id
* @return {Pokemon}
*/
deletePkmn(id) {
let index = this.getPkmnIndexById(id);
let pkmn = this.party[index];
if (pkmn) this.party.splice(index, 1)[0];
if (pkmn) this.party.splice(index, 1);
}
/**

View File

@@ -132,6 +132,9 @@ export default class Player extends MapObject {
case "LEVEL_UP_REWARDS":
resolve(this.LevelUpRewards(msg));
break;
case "RELEASE_POKEMON":
resolve(this.ReleasePokemon(msg));
break;
case "GET_PLAYER_PROFILE":
resolve(this.GetPlayerProfile(msg));
break;
@@ -183,9 +186,11 @@ export default class Player extends MapObject {
inheritByObject(obj) {
for (let key in obj) {
// ignore
if (!(key !== "id")) continue;
if (!(key !== "email")) continue;
if (key === "candies") {
if (key === "id") {
this.uid = obj[key];
}
else if (key === "candies") {
this.candyBag.parseJSON(obj[key]);
}
else if (key === "items") {
@@ -222,28 +227,28 @@ export default class Player extends MapObject {
syncWithDatabase() {
return new Promise((resolve) => {
this.loadFromDatabase().then((row) => {
this.inheritByObject(row);
resolve();
this.loadPlayerDatabase().then((row) => {
this.party.syncWithDatabase().then(() => {
resolve();
});
});
});
}
loadFromDatabase() {
loadPlayerDatabase() {
let query = `SELECT * from ${CFG.MYSQL_USERS_TABLE} WHERE email=? LIMIT 1`;
return new Promise((resolve) => {
this.world.db.query(query, [this.email], (e, rows) => {
if (e) return print(e, 31);
if (rows.length >= 1) resolve(rows[0]);
if (rows.length >= 1) {
this.inheritByObject(rows[0]);
resolve();
}
else print(`Failed to sync player ${this.username} with database!`, 31);
});
});
}
saveIntoDatabase() {
}
refreshPosition() {
let req = this.request;
if (
@@ -258,14 +263,36 @@ export default class Player extends MapObject {
/**
* @param {WildPokemon} pkmn
* @param {String} ball
* @return {Object}
*/
catchPkmn(pkmn) {
catchPkmn(pkmn, ball) {
this.info.exp += 100;
this.info.stardust += 100;
this.info.pkmnCaptured += 1;
this.currentEncounter = null;
this.party.addPkmn(pkmn);
pkmn.owner = this;
pkmn.calcStats();
pkmn.catchedBy(this);
pkmn.pokeball = ball;
return new Promise((resolve) => {
pkmn.insertIntoDatabase().then((insertId) => {
print(insertId, 36);
pkmn.uid = pkmn.insertId;
let partyPkmn = this.party.addPkmn(pkmn);
print(`${this.username} catched a wild ${pkmn.getPkmnName()}!`);
resolve({
status: "CATCH_SUCCESS",
captured_pokemon_id: partyPkmn.uid,
capture_award: {
activity_type: ["ACTIVITY_CATCH_POKEMON"],
xp: [100],
candy: [3],
stardust: [100]
}
});
});
});
}
}

View File

@@ -0,0 +1,28 @@
import POGOProtos from "pokemongo-protobuf";
/**
* @param {Object} msg
* @return {Buffer}
*/
export default function ReleasePokemon(msg) {
let buffer = null;
let pkmn = this.party.getPkmnById(msg.pokemon_id);
if (pkmn) {
this.party.deletePkmn(pkmn.uid);
buffer = {
result: "SUCCESS",
candy_awarded: 0
};
} else {
buffer = {
result: "FAILED"
};
}
return (
POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.ReleasePokemonResponse")
);
}

View File

@@ -8,7 +8,7 @@ export default function SetFavoritePokemon(msg) {
let buffer = null;
let pkmn = this.party.getPkmnById(msg.pokemon_id);
console.log(this.party.party);
if (pkmn) {
pkmn.setFavorite(msg.is_favorite);
buffer = { result: "SUCCESS" };

View File

@@ -2,6 +2,7 @@ export SetAvatar from "./SetAvatar";
export GetPlayer from "./GetPlayer";
export GetInventory from "./GetInventory";
export GetAuthTicket from "./GetAuthTicket";
export ReleasePokemon from "./ReleasePokemon";
export LevelUpRewards from "./LevelUpRewards";
export GetHatchedEggs from "./GetHatchedEggs";
export GetAssetDigest from "./GetAssetDigest";

View File

@@ -11,6 +11,7 @@ export function calcStats() {
this.attack = stats.base_attack;
this.defense = stats.base_defense;
this.stamina = stats.base_stamina;
this.staminaMax = this.stamina;
this.ivAttack = ~~(Math.random() * maxIV) + minIV;
this.ivDefense = ~~(Math.random() * maxIV) + minIV;
@@ -21,6 +22,8 @@ export function calcStats() {
this.cp = this.calcCP();
this.calcMoves();
}
export function calcMoves() {
@@ -30,8 +33,8 @@ export function calcMoves() {
let weakMoves = pkmnTmpl.quick_moves;
let strongMoves = pkmnTmpl.cinematic_moves;
this.move1 = (Math.random() * weakMoves.length) << 0;
this.move2 = (Math.random() * strongMoves.length) << 0;
this.move1 = weakMoves[(Math.random() * weakMoves.length) << 0];
this.move2 = strongMoves[(Math.random() * strongMoves.length) << 0];
}

View File

@@ -7,11 +7,14 @@ import Settings from "../../modes";
import {
_toCC,
inherit,
validName
validName,
deCapitalize
} from "../../utils";
import print from "../../print";
import CFG from "../../../cfg";
import * as _calc from "./calc";
import * as _actions from "./action";
@@ -30,14 +33,13 @@ export default class Pokemon extends MapObject {
super(null);
this.id = 0;
this.dexNumber = 0;
this._level = 1;
this.capturedLevel = 0;
this.cp = 0;
this.cpMultiplier = 0;
this.cpMultiplier = Math.random();
this.addCpMultiplier = 0;
this.move1 = 0;
@@ -87,16 +89,34 @@ export default class Pokemon extends MapObject {
if (this.hasOwnProperty(key)) {
this[key] = obj[key];
}
else if (this.hasOwnProperty(this.normalizeKey(key))) {
this[this.normalizeKey(key)] = obj[key];
}
else if (key === "id") {
this.uid = parseInt(obj[key]);
}
else if (key === "move_1") {
this.move1 = obj[key];
}
else if (key === "move_2") {
this.move2 = obj[key];
}
};
if (obj.isWild) {
this.isWild = true;
}
else {
if (!obj.isWild) {
this.calcStats();
this.calcMoves();
}
}
/**
* @param {String} key
* @return {String}
*/
normalizeKey(key) {
return (
deCapitalize(_toCC(key))
);
}
/**
* @param {Boolean} truth
*/
@@ -164,12 +184,48 @@ export default class Pokemon extends MapObject {
);
}
insertIntoDatabase() {
let query = `
INSERT INTO ${CFG.MYSQL_OWNED_PKMN_TABLE} SET
owner_id=?,
dex_number=?,
cp=?,
stamina=?,
stamina_max=?,
move_1=?,
move_2=?,
height_m=?,
weight_kg=?,
individual_attack=?,
individual_defense=?,
individual_stamina=?,
cp_multiplier=?,
pokeball=?,
favorite=?,
nickname=?
`;
let data = [
this.owner.uid, this.dexNumber, this.cp,
this.stamina, this.staminaMax,
this.move1, this.move2,
this.height, this.weight,
this.ivAttack, this.ivDefense, this.ivStamina,
this.cpMultiplier, this.pokeball, this.favorite, this.nickname || ""
];
return new Promise((resolve) => {
this.owner.world.db.query(query, data, (e, res) => {
if (e) return print(e, 31);
resolve(res.insertId);
});
});
}
/**
* @return {Object}
*/
serialize() {
return ({
id: this.id,
id: this.uid,
pokemon_id: this.dexNumber,
cp: this.cp,
stamina: this.stamina,

View File

@@ -27,14 +27,14 @@ export default class Cell extends MapObject {
super(obj);
this._uPkmnId = 0;
this.synced = false;
this.forts = [];
this.type = obj.type;
this.synced = false;
this.expiration = 0;
}
/**
@@ -48,6 +48,15 @@ export default class Cell extends MapObject {
);
}
delete() {
let index = this.world.getCellIndexByCellId(this.cellId);
let cell = this.world.cells[index];
if (cell) {
this.world.cells.splice(index, 1);
print(`Cell ${cell.cellId} timed out!`, 33);
}
}
/**
* @param {Object} obj
* @return {Fort}
@@ -73,6 +82,7 @@ export default class Cell extends MapObject {
loadForts() {
return new Promise((resolve) => {
this.expiration = +new Date() + CFG.CELL_TIMEOUT;
if (this.synced) {
this.forts.map((fort) => {
this.processDeletedFort(fort);
@@ -182,9 +192,10 @@ 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 || fort.uid === id << 0) return (index);
if (fort.uid === id) return (index);
++index;
};
return (-1);
@@ -230,59 +241,23 @@ export default class Cell extends MapObject {
* @param {Player} player
* @return {Array}
*/
serializeWildPkmns(player) {
serializePkmns(player) {
let ii = 0;
let length = this.forts.length;
let out = [];
let fort = null;
for (; ii < length; ++ii) {
fort = this.forts[ii];
if (!(fort.isSpawn === true)) continue;
fort.activeSpawns.map((encounter) => {
if (!encounter.alreadyCatchedBy(player)) {
out.push(encounter.serializeWild());
}
});
let out = {
wild: [],
nearby: [],
catchable: []
};
return (out);
}
/**
* @param {Player} player
* @return {Array}
*/
serializeCatchablePkmns(player) {
let ii = 0;
let length = this.forts.length;
let out = [];
let fort = null;
for (; ii < length; ++ii) {
fort = this.forts[ii];
if (!(fort.isSpawn === true)) continue;
fort.activeSpawns.map((encounter) => {
if (!encounter.alreadyCatchedBy(player)) {
out.push(encounter.serializeCatchable());
}
});
};
return (out);
}
/**
* @param {Player} player
* @return {Array}
*/
serializeNearbyPkmns(player) {
let ii = 0;
let length = this.forts.length;
let out = [];
let fort = null;
for (; ii < length; ++ii) {
fort = this.forts[ii];
if (!(fort.isSpawn === true)) continue;
fort.activeSpawns.map((encounter) => {
if (!encounter.alreadyCatchedBy(player)) {
out.push(encounter.serializeNearby());
out.wild.push(encounter.serializeWild());
out.nearby.push(encounter.serializeNearby());
out.catchable.push(encounter.serializeCatchable());
}
});
};
@@ -294,7 +269,7 @@ export default class Cell extends MapObject {
* @return {Object}
*/
serialize(player) {
return ({
let buffer = {
s2_cell_id: this.cellId,
current_timestamp_ms: +new Date(),
forts: this.forts.map((fort) => { if (!fort.isSpawn) return fort.serialize(); }),
@@ -302,10 +277,15 @@ export default class Cell extends MapObject {
deleted_objects: [],
fort_summaries: [],
decimated_spawn_points: [],
wild_pokemons: this.serializeWildPkmns(player),
catchable_pokemons: this.serializeCatchablePkmns(player),
nearby_pokemons: this.serializeNearbyPkmns(player)
});
wild_pokemons: null,
catchable_pokemons: null,
nearby_pokemons: null
};
let pkmns = this.serializePkmns(player);
buffer.wild_pokemons = pkmns.wild;
buffer.nearby_pokemons = pkmns.nearby;
buffer.catchable_pokemons = pkmns.catchable;
return (buffer);
}
}

View File

@@ -85,7 +85,7 @@ export default class SpawnPoint extends MapObject {
maxExpire: this.maxExpire
});
this.activeSpawns.push(pkmn);
print(`Spawned ${pkmn.getPkmnName()} at ${this.cellId}`);
print(`Spawned ${pkmn.getPkmnName()}:${pkmn.uid} at ${this.cellId}`);
}
/**

View File

@@ -34,15 +34,24 @@ export default class World {
/**
* @param {String} cellId
* @return {Cell}
* @return {Number}
*/
getCellByCellId(cellId) {
getCellIndexByCellId(cellId) {
let ii = 0;
let length = this.cells.length;
for (; ii < length; ++ii) {
if (this.cells[ii].cellId === cellId) return (this.cells[ii]);
if (this.cells[ii].cellId === cellId) return (ii);
};
return (null);
return (-1);
}
/**
* @param {String} cellId
* @return {Cell}
*/
getCellByCellId(cellId) {
let index = this.getCellIndexByCellId(cellId);
return (this.cells[index] || null);
}
/**
@@ -93,7 +102,7 @@ export default class World {
* @return {WildPokemon}
*/
getEncounterById(id) {
id <<= 0;
id = parseInt(id);
let ii = 0;
let jj = 0;
let fortLength = 0;

View File

@@ -6,47 +6,52 @@ import POGOProtos from "pokemongo-protobuf";
export default function CatchPokemon(msg) {
let buffer = null;
let schema = "POGOProtos.Networking.Responses.CatchPokemonResponse";
let player = msg.player;
let bag = player.bag;
let item = bag.getLocalItemKey(msg.pokeball);
let ball = bag.getLocalItemKey(msg.pokeball);
let pkmn = msg.player.currentEncounter;
player.bag[item] -= 1;
player.bag[ball] -= 1;
// Invalid pkmn
if (!pkmn) {
buffer = {
status: "CATCH_ERROR"
};
// Missed
} else if (!msg.hit_pokemon || !bag[item]) {
buffer = {
status: "CATCH_MISSED"
};
// Escaped
} else if (Math.random() < .35) {
buffer = {
status: "CATCH_ESCAPE"
};
// Catched
} else {
player.catchPkmn(pkmn);
buffer = {
status: "CATCH_SUCCESS",
captured_pokemon_id: pkmn.encounterId,
capture_award: {
activity_type: ["ACTIVITY_CATCH_POKEMON"],
xp: [100],
candy: [3],
stardust: [100]
return new Promise((resolve) => {
// Invalid pkmn
if (!pkmn) {
player.currentEncounter = null;
pkmn.catchedBy(player);
buffer = {
status: "CATCH_ERROR"
};
// Missed
} else if (!msg.hit_pokemon || !bag[ball]) {
buffer = {
status: "CATCH_MISSED"
};
} else {
// Fleed
if (Math.random() < .1) {
pkmn.catchedBy(player);
player.currentEncounter = null;
buffer = {
status: "CATCH_FLEE"
};
// Escaped
} else if (Math.random() < .2) {
buffer = {
status: "CATCH_ESCAPE"
};
// Catched?
} else {
player.catchPkmn(pkmn, msg.pokeball).then((result) => {
resolve(POGOProtos.serialize(result, schema));
});
return void 0;
}
};
}
return (
POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.CatchPokemonResponse")
);
}
resolve(POGOProtos.serialize(buffer, schema));
});
}

View File

@@ -211,8 +211,8 @@ export function authenticatePlayer(player) {
deXOR(this.hash, getHashCodeFrom(this.claim)) === this.repository
);
// Register player
this.world.playerIsRegistered(player.email).then((truth) => {
// Register
if (!truth) {
this.world.registerPlayer(player).then((id) => {
player.syncWithDatabase().then(() => {
@@ -220,6 +220,7 @@ export function authenticatePlayer(player) {
});
});
}
// Login
else {
player.syncWithDatabase().then(() => {
player.sendResponse(msg);

View File

@@ -43,6 +43,7 @@ export function processResponse(player, req) {
case "SET_AVATAR":
case "GET_PLAYER":
case "GET_INVENTORY":
case "RELEASE_POKEMON":
case "GET_ASSET_DIGEST":
case "GET_HATCHED_EGGS":
case "LEVEL_UP_REWARDS":

View File

@@ -20,7 +20,7 @@ export function inherit(cls, prot) {
}
let hashIndex = 0;
let hashIndex = 1;
/**
* @return {Number}
@@ -99,6 +99,16 @@ export function capitalize(str) {
);
}
/**
* @param {String} str
* @return {String}
*/
export function deCapitalize(str) {
return (
str[0].toLowerCase() + str.slice(1)
);
}
let rx_username = /[^a-z\d]/i;
export function validUsername(str) {
return (