mirror of
https://github.com/maierfelix/POGOserver.git
synced 2026-04-12 20:55:49 -05:00
Update
- Spawn cycle - Fixed avatar gender change - Basic wild pokemon - Basic map encounter spawns - Store cells inside array instead of object, to improve performance - Increased map visibility range dramatically - Lint game master parsing
This commit is contained in:
parent
2de38e5568
commit
00793fd42d
|
|
@ -1,6 +1,9 @@
|
|||
import print from "./print";
|
||||
import CFG from "../cfg";
|
||||
|
||||
import Settings from "./modes";
|
||||
const MAP_REFRESH_RATE = Settings.GAME_SETTINGS.map_settings.get_map_objects_max_refresh_seconds;
|
||||
|
||||
export function startCycle() {
|
||||
this.cycleInstance = setTimeout(() => this.cycle(), CFG.TICK_INTERVAL);
|
||||
}
|
||||
|
|
@ -51,6 +54,12 @@ export function resetTimers() {
|
|||
//this.saveAllPlayers();
|
||||
this.saveTick = 0;
|
||||
}
|
||||
this.spawnTick++;
|
||||
// Pkmn spawn interval
|
||||
if (this.spawnTick >= MAP_REFRESH_RATE * 1e3) {
|
||||
this.world.spawnEncounters();
|
||||
this.spawnTick = 0;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ export default class GameServer {
|
|||
this.time = 0;
|
||||
this.fullTick = 0;
|
||||
this.saveTick = 0;
|
||||
this.spawnTick = 0;
|
||||
this.timeoutTick = 0;
|
||||
this.passedTicks = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,34 @@
|
|||
import fs from "fs";
|
||||
import POGOProtos from "pokemongo-protobuf";
|
||||
|
||||
import {
|
||||
idToPkmnBundleName
|
||||
} from "../../utils";
|
||||
|
||||
import CFG from "../../../cfg";
|
||||
import ENUM from "../../enum";
|
||||
|
||||
import print from "../../print";
|
||||
|
||||
/**
|
||||
* @class GameMaster
|
||||
*/
|
||||
export default class GameMaster {
|
||||
|
||||
/**
|
||||
* @param {Object} decode
|
||||
* @param {GameServer} instance
|
||||
* @constructor
|
||||
*/
|
||||
constructor(decode) {
|
||||
constructor(instance) {
|
||||
|
||||
this.instance = instance;
|
||||
|
||||
this.settings = this.buildSettings();
|
||||
|
||||
this.decode = decode;
|
||||
this.decode = this.parse();
|
||||
this.buffer = this.encode();
|
||||
|
||||
this.parse();
|
||||
this.parseItemTemplates();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -36,6 +42,17 @@ export default class GameMaster {
|
|||
}
|
||||
|
||||
parse() {
|
||||
let master = null;
|
||||
try {
|
||||
let data = fs.readFileSync(CFG.DUMP_ASSET_PATH + "game_master");
|
||||
master = this.instance.parseProtobuf(data, "POGOProtos.Networking.Responses.DownloadItemTemplatesResponse");
|
||||
} catch (e) {
|
||||
print(e, 31);
|
||||
}
|
||||
return (master);
|
||||
}
|
||||
|
||||
parseItemTemplates() {
|
||||
|
||||
let item = null;
|
||||
let items = this.decode.item_templates;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export default class Avatar {
|
|||
return (this._pants);
|
||||
}
|
||||
set pants(value) {
|
||||
if (this.between(value, 0, 2)) {
|
||||
if (this.between(value, 0, 5)) {
|
||||
this._pants = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -125,6 +125,17 @@ export default class Avatar {
|
|||
}
|
||||
}
|
||||
|
||||
resetOutfit() {
|
||||
this.skin = 0;
|
||||
this.hair = 0;
|
||||
this.shirt = 0;
|
||||
this.pants = 0;
|
||||
this.hat = 0;
|
||||
this.shoes = 0;
|
||||
this.eyes = 0;
|
||||
this.backpack = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
|
|
@ -149,7 +160,7 @@ export default class Avatar {
|
|||
let obj = JSON.parse(str);
|
||||
for (let key in obj) {
|
||||
if (this.hasOwnProperty("_" + key)) {
|
||||
this[key] = obj[key];
|
||||
this[key] = obj[key] << 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ export default class Player extends MapObject {
|
|||
|
||||
this.remoteAddress = null;
|
||||
|
||||
this.currentEncounter = null;
|
||||
|
||||
this.bag = new Bag(this);
|
||||
this.candyBag = new CandyBag(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,19 @@ import POGOProtos from "pokemongo-protobuf";
|
|||
*/
|
||||
export default function SetAvatar(msg) {
|
||||
|
||||
if (!msg.player_avatar.hasOwnProperty("gender")) {
|
||||
msg.player_avatar.gender = "MALE";
|
||||
}
|
||||
|
||||
let gender = msg.player_avatar.gender;
|
||||
let genderChange = this.avatar.gender !== gender;
|
||||
|
||||
msg.player_avatar.gender = gender === "MALE" ? 0 : 1;
|
||||
|
||||
if (genderChange) {
|
||||
this.avatar.resetOutfit();
|
||||
}
|
||||
|
||||
for (let key in msg.player_avatar) {
|
||||
this.avatar[key] = msg.player_avatar[key];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
import s2 from "s2-geometry";
|
||||
import Pokemon from "../index";
|
||||
//import CaptureProbability from "CaptureProbability";
|
||||
|
||||
import Settings from "../../../modes";
|
||||
|
||||
import { getHashCodeFrom } from "../../../utils";
|
||||
|
||||
const S2Geo = s2.S2;
|
||||
|
||||
const MAP_REFRESH_RATE = Settings.GAME_SETTINGS.map_settings.get_map_objects_max_refresh_seconds;
|
||||
const EXPIRE_MULTIPLIER = Settings.PKMN_SETTINGS.EXPIRE_MULTIPLIER;
|
||||
|
||||
/**
|
||||
* @class WildPokemon
|
||||
*/
|
||||
class WildPokemon extends Pokemon {
|
||||
export default class WildPokemon extends Pokemon {
|
||||
|
||||
/**
|
||||
* @param {Object} obj
|
||||
|
|
@ -15,14 +24,80 @@ class WildPokemon extends Pokemon {
|
|||
super(obj);
|
||||
|
||||
this.encounterId = 0;
|
||||
this.spawnPointId = 0;
|
||||
|
||||
this.latitude = 0;
|
||||
this.longitude = 0;
|
||||
this.creation = +new Date();
|
||||
|
||||
this.pokeball = 0;
|
||||
this.expiration = ~~(Math.random() * (MAP_REFRESH_RATE * 1e3) * EXPIRE_MULTIPLIER) + (MAP_REFRESH_RATE * 1e3);
|
||||
|
||||
this.spawnPoint = 0;
|
||||
this.setRandomPosition();
|
||||
|
||||
this.uid = Math.random() * 1e5 << 0;
|
||||
|
||||
}
|
||||
|
||||
setRandomPosition() {
|
||||
let pos = S2Geo.idToLatLng(this.cellId);
|
||||
this.latitude = pos.lat + (Math.random() * .009) + .0002;
|
||||
this.longitude = pos.lng + (Math.random() * .009) + .0002;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isExpired() {
|
||||
return (
|
||||
+new Date() >= this.creation + this.expiration
|
||||
);
|
||||
}
|
||||
|
||||
getEncounterId() {
|
||||
return (getHashCodeFrom(this.cellId + "" + this.uid));
|
||||
}
|
||||
|
||||
getPkmnId() {
|
||||
return (
|
||||
this.getPkmnName().toUpperCase()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
serializeWild() {
|
||||
return ({
|
||||
encounter_id: this.getEncounterId(),
|
||||
last_modified_timestamp_ms: +new Date(),
|
||||
latitude: this.latitude,
|
||||
longitude: this.longitude,
|
||||
pokemon_data: {
|
||||
pokemon_id: this.getPkmnId()
|
||||
},
|
||||
time_till_hidden_ms: this.expiration
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
serializeCatchable() {
|
||||
return ({
|
||||
encounter_id: this.getEncounterId(),
|
||||
pokemon_id: this.getPkmnId(),
|
||||
expiration_timestamp_ms: this.creation + this.expiration,
|
||||
latitude: this.latitude,
|
||||
longitude: this.longitude
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
serializeNearby() {
|
||||
return ({
|
||||
pokemon_id: this.getPkmnId(),
|
||||
encounter_id: this.getEncounterId()
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -62,6 +62,8 @@ export default class Pokemon extends MapObject {
|
|||
this.nickname = null;
|
||||
this.pokeball = null;
|
||||
|
||||
this.isWild = false;
|
||||
|
||||
this.init(obj);
|
||||
|
||||
}
|
||||
|
|
@ -84,8 +86,13 @@ export default class Pokemon extends MapObject {
|
|||
this[key] = obj[key];
|
||||
}
|
||||
};
|
||||
this.calcStats();
|
||||
this.calcMoves();
|
||||
if (obj.isWild) {
|
||||
this.isWild = true;
|
||||
}
|
||||
else {
|
||||
this.calcStats();
|
||||
this.calcMoves();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import s2 from "s2-geometry";
|
||||
import rare from "pokerare";
|
||||
|
||||
import Gym from "../Fort/Gym";
|
||||
import Pokestop from "../Fort/Pokestop";
|
||||
|
||||
import WildPokemon from "../../Pokemon/WildPokemon";
|
||||
|
||||
import MapObject from "../MapObject";
|
||||
import Settings from "../../../modes";
|
||||
import CFG from "../../../../cfg";
|
||||
|
|
@ -25,14 +28,26 @@ export default class Cell extends MapObject {
|
|||
|
||||
super(obj);
|
||||
|
||||
this._uPkmnId = 0;
|
||||
|
||||
this.synced = false;
|
||||
|
||||
this.forts = [];
|
||||
|
||||
this.encounters = [];
|
||||
|
||||
this.type = obj.type;
|
||||
|
||||
}
|
||||
|
||||
get uPkmnId() {
|
||||
return (this._uPkmnId);
|
||||
}
|
||||
set uPkmnId(value) {
|
||||
if (this.uPkmnId < Number.MAX_SAFE_INTEGER) this._uPkmnId += value;
|
||||
else this._uPkmnId = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} lat
|
||||
* @param {Number} lng
|
||||
|
|
@ -44,6 +59,63 @@ export default class Cell extends MapObject {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} obj
|
||||
* @return {Fort}
|
||||
*/
|
||||
addFort(obj) {
|
||||
obj.world = this.world;
|
||||
let fort = null;
|
||||
fort = obj.type === "CHECKPOINT" ? new Pokestop(obj) : new Gym(obj);
|
||||
this.forts.push(fort);
|
||||
return (fort);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {WildPokemon}
|
||||
*/
|
||||
addEncounter() {
|
||||
let pkmn = this.getRandomEncounter();
|
||||
print(`Spawned 1x ${pkmn.getPkmnName()} at ${this.cellId}`);
|
||||
this.encounters.push(pkmn);
|
||||
return (pkmn);
|
||||
}
|
||||
|
||||
getRandomEncounter() {
|
||||
let ids = rare.getPkmnByRarity(255, 255);
|
||||
let index = Math.floor(Math.random() * ids.length);
|
||||
return new WildPokemon({
|
||||
dexNumber: ids[index].id,
|
||||
pokeball: "ITEM_POKE_BALL",
|
||||
favorite: 0,
|
||||
isWild: true,
|
||||
uid: this.uPkmnId++,
|
||||
cellId: this.cellId
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {WildPokemon} encounter
|
||||
*/
|
||||
removeEncounter(encounter) {
|
||||
let index = 0;
|
||||
this.encounters.map((pkmn) => {
|
||||
if (pkmn.uid === encounter.uid) {
|
||||
print(`Killed 1x ${pkmn.getPkmnName()} at ${this.cellId}`, 33);
|
||||
this.encounters.splice(index, 1);
|
||||
}
|
||||
index++;
|
||||
});
|
||||
}
|
||||
|
||||
refreshEncounters() {
|
||||
this.encounters.map((encounter) => {
|
||||
if (encounter.isExpired()) {
|
||||
this.removeEncounter(encounter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadForts() {
|
||||
return new Promise((resolve) => {
|
||||
if (this.synced) {
|
||||
|
|
@ -165,15 +237,21 @@ export default class Cell extends MapObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Object} obj
|
||||
* @return {Fort}
|
||||
* @return {Object}
|
||||
*/
|
||||
addFort(obj) {
|
||||
obj.world = this.world;
|
||||
let fort = null;
|
||||
fort = obj.type === "CHECKPOINT" ? new Pokestop(obj) : new Gym(obj);
|
||||
this.forts.push(fort);
|
||||
return (fort);
|
||||
serialize() {
|
||||
return ({
|
||||
s2_cell_id: this.cellId,
|
||||
current_timestamp_ms: +new Date(),
|
||||
forts: this.forts.map((fort) => { return fort.serialize(); }),
|
||||
spawn_points: [],
|
||||
deleted_objects: [],
|
||||
fort_summaries: [],
|
||||
decimated_spawn_points: [],
|
||||
wild_pokemons: this.encounters.map((pkmn) => { return pkmn.serializeWild(); }),
|
||||
catchable_pokemons: this.encounters.map((pkmn) => { return pkmn.serializeCatchable(); }),
|
||||
nearby_pokemons: this.encounters.map((pkmn) => { return pkmn.serializeNearby(); })
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ export function getFortsByCells(cells, out, index) {
|
|||
*/
|
||||
export function getFortsByCellId(cellId) {
|
||||
return new Promise((resolve) => {
|
||||
if (!this.cellRegistered(cellId)) {
|
||||
if (!this.cellAlreadyRegistered(cellId)) {
|
||||
this.registerCell(cellId).then((cell) => {
|
||||
resolve(cell);
|
||||
});
|
||||
|
|
@ -68,7 +68,7 @@ export function registerCell(cellId) {
|
|||
world: this,
|
||||
cellId: cellId
|
||||
});
|
||||
this.cells[cellId] = cell;
|
||||
this.cells.push(cell);
|
||||
return new Promise((resolve) => {
|
||||
cell.loadForts().then(() => {
|
||||
resolve(this.getCellById(cellId));
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default class World {
|
|||
|
||||
this.players = [];
|
||||
|
||||
this.cells = {};
|
||||
this.cells = [];
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -30,15 +30,27 @@ export default class World {
|
|||
return (this.players.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} cellId
|
||||
* @return {Cell}
|
||||
*/
|
||||
getCellByCellId(cellId) {
|
||||
let ii = 0;
|
||||
let length = this.cells.length;
|
||||
for (; ii < length; ++ii) {
|
||||
if (this.cells[ii].cellId === cellId) return (this.cells[ii]);
|
||||
};
|
||||
return (null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} cellId
|
||||
* @return {Boolean}
|
||||
*/
|
||||
cellRegistered(cellId) {
|
||||
cellAlreadyRegistered(cellId) {
|
||||
let cell = this.getCellByCellId(cellId);
|
||||
return (
|
||||
this.cells[cellId] !== null &&
|
||||
this.cells[cellId] !== void 0 &&
|
||||
this.cells[cellId]
|
||||
cell !== null
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -47,15 +59,24 @@ export default class World {
|
|||
* @return {Cell}
|
||||
*/
|
||||
getCellById(cellId) {
|
||||
return (this.cells[cellId]);
|
||||
return (this.getCellByCellId(cellId));
|
||||
}
|
||||
|
||||
addGym() {
|
||||
|
||||
}
|
||||
spawnEncounters() {
|
||||
|
||||
let ii = 0;
|
||||
let length = this.cells.length;
|
||||
|
||||
let cell = null;
|
||||
|
||||
for (; ii < length; ++ii) {
|
||||
cell = this.cells[ii];
|
||||
if (Math.random() < .25 && cell.encounters.length <= 3) {
|
||||
cell.addEncounter();
|
||||
}
|
||||
cell.refreshEncounters();
|
||||
};
|
||||
|
||||
addWildPokemon() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -65,6 +86,11 @@ export default class World {
|
|||
getPacket(type, msg) {
|
||||
return new Promise((resolve) => {
|
||||
switch (type) {
|
||||
case "ENCOUNTER":
|
||||
this.Encounter(msg).then((result) => {
|
||||
resolve(result);
|
||||
});
|
||||
break;
|
||||
case "FORT_SEARCH":
|
||||
this.FortSearch(msg).then((result) => {
|
||||
resolve(result);
|
||||
|
|
|
|||
14
src/models/World/packets/Encounter.js
Normal file
14
src/models/World/packets/Encounter.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import POGOProtos from "pokemongo-protobuf";
|
||||
|
||||
/**
|
||||
* @param {Object} msg
|
||||
*/
|
||||
export default function Encounter(msg) {
|
||||
|
||||
let buffer = {};
|
||||
|
||||
return (
|
||||
POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.EncounterResponse")
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -30,18 +30,7 @@ export default function GetMapObjects(msg) {
|
|||
else ids.push(id);
|
||||
});
|
||||
}
|
||||
mapCells.push({
|
||||
s2_cell_id: cell.cellId,
|
||||
current_timestamp_ms: +new Date(),
|
||||
forts: cell.forts.map((fort) => { return fort.serialize() }),
|
||||
spawn_points: [],
|
||||
deleted_objects: [],
|
||||
fort_summaries: [],
|
||||
decimated_spawn_points: [],
|
||||
wild_pokemons: [],
|
||||
catchable_pokemons: [],
|
||||
nearby_pokemons: []
|
||||
});
|
||||
mapCells.push(cell.serialize());
|
||||
});
|
||||
resolve(
|
||||
POGOProtos.serialize(buffer, "POGOProtos.Networking.Responses.GetMapObjectsResponse")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export Encounter from "./Encounter";
|
||||
export FortSearch from "./FortSearch";
|
||||
export FortDetails from "./FortDetails";
|
||||
export GetMapObjects from "./GetMapObjects";
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ export default {
|
|||
far_interaction_range_meters: 1000.0156862745098
|
||||
},
|
||||
map_settings: {
|
||||
pokemon_visible_range: 70.00196078431372,
|
||||
pokemon_visible_range: 999.00196078431372,
|
||||
poke_nav_range_meters: 751.0156862745098,
|
||||
encounter_range_meters: 50.25098039215686,
|
||||
encounter_range_meters: 999.25098039215686,
|
||||
get_map_objects_min_refresh_seconds: 16,
|
||||
get_map_objects_max_refresh_seconds: 16,
|
||||
get_map_objects_min_distance_meters: 10.007843017578125,
|
||||
|
|
@ -30,6 +30,7 @@ export default {
|
|||
},
|
||||
PKMN_SETTINGS: {
|
||||
MIN_IV: 1,
|
||||
MAX_IV: 15
|
||||
MAX_IV: 15,
|
||||
EXPIRE_MULTIPLIER: 5
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ export function processResponse(player, req) {
|
|||
return void 0;
|
||||
break;
|
||||
// Global
|
||||
case "ENCOUNTER":
|
||||
case "FORT_SEARCH":
|
||||
case "FORT_DETAILS":
|
||||
case "GET_MAP_OBJECTS":
|
||||
|
|
|
|||
21
src/setup.js
21
src/setup.js
|
|
@ -39,8 +39,7 @@ export function setup() {
|
|||
|
||||
print(`Downloaded assets are valid! Proceeding..`);
|
||||
|
||||
let parsedMaster = this.parseGameMaster();
|
||||
shared.GAME_MASTER = new GameMaster(parsedMaster);
|
||||
shared.GAME_MASTER = new GameMaster(this);
|
||||
|
||||
this.setupDatabaseConnection().then(() => {
|
||||
if (CFG.PORT < 1) {
|
||||
|
|
@ -93,9 +92,8 @@ export function validateModels() {
|
|||
|
||||
return new Promise((resolve, reject) => {
|
||||
const validate = (index) => {
|
||||
let platform = pogo.platforms[index];
|
||||
let name = platform.name;
|
||||
let path = CFG.DUMP_ASSET_PATH + name + "/";
|
||||
let platform = pogo.platforms[index].name;
|
||||
let path = CFG.DUMP_ASSET_PATH + platform + "/";
|
||||
|
||||
// ups, validate asset_digest's too
|
||||
if (!this.fileExists(path + "asset_digest")) {
|
||||
|
|
@ -103,7 +101,7 @@ export function validateModels() {
|
|||
}
|
||||
else {
|
||||
let buffer = fs.readFileSync(path + "asset_digest");
|
||||
shared.GAME_ASSETS[name] = {
|
||||
shared.GAME_ASSETS[platform] = {
|
||||
buffer: buffer,
|
||||
decode: this.parseProtobuf(buffer, "POGOProtos.Networking.Responses.GetAssetDigestResponse")
|
||||
};
|
||||
|
|
@ -130,17 +128,6 @@ export function validateModels() {
|
|||
|
||||
}
|
||||
|
||||
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");
|
||||
} catch (e) {
|
||||
print(e, 31);
|
||||
}
|
||||
return (master);
|
||||
}
|
||||
|
||||
export function onFirstRun(resolve) {
|
||||
print(`Attempt to login with ${_toCC(CFG.DOWNLOAD_PROVIDER)}..`, 33);
|
||||
pogo.login({
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user