Added mongodb, many updates & bug fixes

- Added mongodb database
- Removed dumps
- Added jwt google auth decode plugin
- Added long decode plugin
- Updated protos to latest commit
- Updated readme
- Added avatar saving
- Fixed bug, where username, level and exp didnt got displayed
- Default username is "undefined"
- Clear console stdin
- Save players into db stdin
- Seperated login/register phase
- Added decode long util method
This commit is contained in:
Felix
2016-08-08 22:25:28 +02:00
parent dbddba2eee
commit e9ccb672dc
30 changed files with 662 additions and 17469 deletions

View File

@@ -0,0 +1,103 @@
import mongodb from "mongodb";
import * as CFG from "../cfg";
/**
* @param {Function} resolve
*/
export function setupMongo(resolve) {
mongodb.MongoClient.connect(CFG.SERVER_MONGO_URL, (error, db) => {
if (error) {
this.print("Unable to connect to database", 31);
} else {
this.db.instance = db;
this.loadCollection(CFG.SERVER_MONGO_COLLECTION_USERS).then(() => {
resolve();
});
}
});
}
export function loadCollection(name) {
return new Promise((resolve) => {
this.db.instance.listCollections({name: name}).next((err, exists) => {
if (!exists) this.createCollection(name).then((coll) => resolve());
else {
this.db.instance.collection(name, (err, coll) => {
resolve();
});
}
});
});
}
export function createCollection(name) {
return new Promise((resolve) => {
this.db.instance.createCollection(name, {}, (err, coll) => {
resolve();
});
});
}
export function getUserByEmail(email) {
return new Promise((resolve) => {
let collection = this.getUserCollection();
collection.find({email: email}).toArray((err, docs) => {
resolve(docs);
});
});
}
export function getUserCollection() {
return (
this.db.instance.collection(CFG.SERVER_MONGO_COLLECTION_USERS)
);
}
export function createUser(obj) {
let collection = this.getUserCollection();
let user = {
username: obj.username,
email: obj.email,
position: obj.position,
exp: obj.exp,
stardust: obj.stardust,
pokecoins: obj.pokecoins,
avatar: obj.avatar
};
return new Promise((resolve) => {
collection.insert([user], (error, result) => {
resolve();
});
});
}
export function updateUser(obj) {
let collection = this.getUserCollection();
let user = {
username: obj.username,
email: obj.email,
position: obj.position,
exp: obj.exp,
stardust: obj.stardust,
pokecoins: obj.pokecoins,
avatar: obj.avatar
};
return new Promise((resolve) => {
collection.update({email: obj.email}, user, (error, result) => {
resolve();
});
});
}

View File

@@ -1,9 +1,11 @@
import fs from "fs";
import http from "http";
import proto from "./proto";
import querystring from "querystring";
import { inherit } from "./utils";
import {
inherit,
decodeLong
} from "./utils";
import * as CFG from "../cfg";
@@ -30,6 +32,11 @@ class GameServer {
CRASH: false
};
this.db = {
instance: null,
collections: {}
};
this.proto = null;
this.socket = null;
this.player = null;

View File

@@ -0,0 +1,18 @@
import proto from "../proto";
/**
* @param {Object}
* @return {Object}
*/
export default function DownloadUrlEntry(obj) {
return (
new proto.Data.DownloadUrlEntry({
url: obj.url,
asset_id: obj.id,
size: obj.size,
checksum: obj.checksum
})
);
}

View File

@@ -11,7 +11,7 @@ export default function ResponseEnvelope(obj) {
status_code: obj.status,
unknown6: new proto.Networking.Envelopes.Unknown6Response({
response_type: 6,
response_data: new proto.Networking.Envelopes.Unknown6Response.Unknown2({
unknown2: new proto.Networking.Envelopes.Unknown6Response.Unknown2({
unknown1: 1
})
}),

View File

@@ -26,7 +26,7 @@ export default function DownloadSettings(obj) {
get_map_objects_min_refresh_seconds: 5,
get_map_objects_max_refresh_seconds: 30,
get_map_objects_min_distance_meters: 10,
google_maps_api_key: "AIzaSyDF9rkP8lhcddBtvH9gVFzjnNo13WtmJIM"
google_maps_api_key: CFG.SERVER_GMAPS_API_KEY
}),
inventory_settings: new proto.Settings.InventorySettings({
max_pokemon: 1000,

View File

@@ -0,0 +1,25 @@
import proto from "../proto";
import DownloadUrlEntry from "./Data.DownloadUrlEntry";
/**
* @return {Object}
*/
export default function GetDownloadUrls() {
let download_urls = [
DownloadUrlEntry({
url: "",
asset_id: "",
size: 0,
checksum: 0
})
];
return (
new proto.Networking.Responses.GetDownloadUrlsResponse({
download_urls: download_urls
}).encode()
);
}

View File

@@ -10,37 +10,81 @@ export default function GetInventoryData(obj) {
new proto.Networking.Responses.GetInventoryResponse({
success: true,
inventory_delta: new proto.Inventory.InventoryDelta({
original_timestamp_ms: new Date().getTime * 1000,
new_timestamp_ms: new Date().getTime * 1000,
inventory_items: [
// player stats
new proto.Inventory.InventoryItem({
inventory_item_data: new proto.Inventory.InventoryItemData({
pokemon_data: new proto.Data.PokemonData({
id: 123781297398,
pokemon_id: 25,
cp: 10000000000,
is_egg: false,
height_m: 100,
weight_kg: 1,
move_1: 219,
move_2: 26,
deployed_fort_id: 0,
owner_name: "",
origin: 0,
individual_attack: 100,
individual_defense: 100,
individual_stamina: 100,
cp_multiplier: 100,
pokeball: 1,
creation_time_ms: new Date().getTime() * 1000
"player_stats": new proto.Data.Player.PlayerStats({
"level": 99,
"experience": 1304364,
"prev_level_xp": 900000,
"next_level_xp": 1350000,
"km_walked": 54.55459213256836,
"pokemons_encountered": 3942,
"unique_pokedex_entries": 93,
"pokemons_captured": 3569,
"evolutions": 782,
"poke_stop_visits": 3113,
"pokeballs_thrown": 5783,
"eggs_hatched": 27,
"big_magikarp_caught": 11,
"battle_attack_won": 36,
"battle_attack_total": 44,
"battle_defended_won": 0,
"battle_training_won": 1,
"battle_training_total": 2,
"prestige_raised_total": 190,
"prestige_dropped_total": 27000,
"pokemon_deployed": 2,
"small_rattata_caught": 79
})
})
}),
// pokedex entry
new proto.Inventory.InventoryItem({
inventory_item_data: new proto.Inventory.InventoryItemData({
item: new proto.Inventory.Item({
item_id: 4,
count: 1000
"pokedex_entry": new proto.Data.PokedexEntry({
"pokemon_id": 147,
"times_encountered": 7,
"times_captured": 6,
"evolution_stone_pieces": 0,
"evolution_stones": 0
})
})
}),
// pokemon
new proto.Inventory.InventoryItem({
inventory_item_data: new proto.Inventory.InventoryItemData({
"pokemon_data": new proto.Data.PokemonData({
"id": 151,
"pokemon_id": 151,
"cp": 9454,
"stamina": 53,
"stamina_max": 53,
"move_1": 221,
"move_2": 80,
"deployed_fort_id": "",
"owner_name": "",
"is_egg": false,
"egg_km_walked_target": 0,
"egg_km_walked_start": 0,
"origin": 0,
"height_m": 0.3461824357509613,
"weight_kg": 2.0753486156463623,
"individual_attack": 2,
"individual_defense": 0,
"individual_stamina": 9,
"cp_multiplier": 0.5974000096321106,
"pokeball": 2,
"battles_attacked": 0,
"battles_defended": 0,
"egg_incubator_id": "",
"creation_time_ms": new Date().getTime() * 1000,
"num_upgrades": 0,
"additional_cp_multiplier": 0,
"favorite": 0,
"nickname": "Ad°0lf_fH$TL3R",
"from_fort": 0
})
})
})

View File

@@ -0,0 +1,52 @@
import proto from "../proto";
/**
* @param {Request} request
* @return {Object}
*/
export default function GetMapObjects(request) {
var cells = proto.Networking.Requests.Messages.GetMapObjectsMessage.decode(request.request_message.toBuffer()).cell_id;
var cellsRes = [];
cells.forEach((cell)=>{
cellsRes.push(new proto.Map.MapCell({
s2_cell_id: cell,
current_timestamp_ms: new Date().getTime() * 1000,
forts: [
new proto.Map.Fort.FortData({
id: "wuff",
last_modified_timestamp_ms: new Date().getTime() * 1000,
latitude: 39.1893730163574220,
longitude: -96.5853271484375000,
owned_by_team: 2,
guard_pokemon_id: 150,
guard_pokemon_cp: 2000,
gym_points: 1000,
is_in_battle: false,
enabled: true,
type: proto.Map.Fort.FortType.GYM,
sponsor: proto.Map.Fort.FortSponsor.MCDONALDS,
rendering_type: proto.Map.Fort.FortRenderingType.DEFAULT
})
],
spawn_points: [ ],
deleted_objects: [ ],
is_truncated_list: false,
fort_summaries: [ ],
decimated_spawn_points: [ ],
wild_pokemons: [ ],
catchable_pokemons: [ ],
nearby_pokemons: [ ]
}));
});
return (
new proto.Networking.Responses.GetMapObjectsResponse({
status: 1,
map_cells: cellsRes
}).encode()
);
}

View File

@@ -10,7 +10,7 @@ function getPlayerDataPacket(obj) {
new proto.Data.PlayerData({
creation_timestamp_ms: 1467936859925,
username: obj.username,
team: obj.team,
team: proto.Enums.TeamColor.YELLOW,
tutorial_state: obj.tutorial_state,
avatar: new proto.Data.Player.PlayerAvatar(obj.avatar),
max_pokemon_storage: 250,
@@ -18,7 +18,6 @@ function getPlayerDataPacket(obj) {
daily_bonus: new proto.Data.Player.DailyBonus({
next_defender_bonus_collect_timestamp_ms: 1470174535972
}),
// equipped_badge: new proto.Data.Player.EquippedBadge({}),
contact_settings: new proto.Data.Player.ContactSettings({
send_marketing_emails: true
}),
@@ -40,17 +39,25 @@ function buildPlayerData(obj) {
let pokecoins = obj.pokecoins;
let stardust = obj.stardust;
let avatar = {
skin: 2,
let avatar = obj.avatar || {
skin: 0,
hair: 2,
shirt: 1,
pants: 2,
hat: 1,
hat: 0,
shoes: 2,
eyes: 3,
gender: proto.Enums.Gender.MALE,
backpack: 1
};
let tutorial_state = [0, 1, 3, 4, 7];
let tutorial_state = [
proto.Enums.TutorialState.LEGAL_SCREEN,
proto.Enums.TutorialState.AVATAR_SELECTION,
proto.Enums.TutorialState.POKEMON_CAPTURE,
proto.Enums.TutorialState.NAME_SELECTION,
proto.Enums.TutorialState.FIRST_TIME_EXPERIENCE_COMPLETE
];
let currencies = [
new proto.Data.Player.Currency({
@@ -87,7 +94,7 @@ export default function GetPlayer(obj) {
new proto.Networking.Responses.GetPlayerResponse({
success: true,
player_data: packet
}).encode()
})
);
}

View File

@@ -49,6 +49,7 @@ export default function ItemTemplates(obj) {
"damage_window_end_ms": 3400,
"energy_delta": -20
}),
// unused but saved here for later use
move_sequence_settings: new proto.Settings.Master.MoveSequenceSettings({
"sequence": ["anim attacker atk-move", "f2fvfx attacker acid_fast", "sfx attacker 051-0_acid", "wait 0.15", "vfx defender acid_fast_hit", "anim defender damageS01", "wait 0.35", "sys ui-sync", "sys complete"]
}),

View File

@@ -7,8 +7,11 @@ export GetInventory from "./Responses.GetInventory";
export GetPlayer from "./Responses.GetPlayer";
export GetPlayerProfile from "./Responses.GetPlayerProfile";
export GetMapObjects from "./Responses.GetMapObjects";
export ItemTemplates from "./Responses.ItemTemplates";
export CheckAwardedBadges from "./Responses.CheckAwardedBadges";
export GetDownloadUrls from "./Responses.GetDownloadUrls";
export AuthTicket from "./Envelopes.AuthTicket";
export ResponseEnvelope from "./Envelopes.ResponseEnvelope";

View File

@@ -17,10 +17,9 @@ class Player {
this.uid = -1;
this.name = null;
this.email = null;
this._username = "undefined";
this.position = {
latitude: 0,
longitude: 0,
@@ -59,6 +58,16 @@ class Player {
this.uid = getHashCodeFrom(String(email));
}
updateByObject(obj) {
for (let key in obj) {
if (this.hasOwnProperty(key)) {
this[key] = obj[key];
}
};
}
/**
* @param {Request} req
*/
@@ -74,6 +83,21 @@ class Player {
}
updateAvatar(req) {
let data = proto.Networking.Requests.Messages.SetAvatarMessage.decode(req.request_message.toBuffer());
this.avatar = data.player_avatar;
}
get username() {
return (this._username);
}
set username(name) {
this._username = name;
}
get latitude() {
return (this.position.latitude);
}
@@ -175,7 +199,10 @@ export function updatePlayers() {
}
export function savePlayers() {
this.print("Saving players into database..");
for (let client of this.clients) {
this.savePlayer(client);
};
this.print("Saved players into database");
return void 0;
}
@@ -183,6 +210,6 @@ export function savePlayers() {
* @param {Player} player
*/
export function savePlayer(player) {
this.print(`${player.remoteAddress} saved into database`, 34);
return void 0;
this.updateUser(player);
//this.print(`${player.remoteAddress} saved into database`, 34);
}

View File

@@ -12,6 +12,13 @@ export function processCommand(cmd, data) {
this.print("Killed the server!", 31);
process.exit();
break;
case "/clear":
process.stdout.write("\x1Bc");
this.greet();
break;
case "/save":
this.savePlayers();
break;
};
};

View File

@@ -16,7 +16,9 @@ import {
GetPlayer,
GetPlayerProfile,
ItemTemplates,
GetAssetDigest
GetAssetDigest,
GetDownloadUrls,
GetMapObjects
} from "./packets";
import { decodeRequestEnvelope } from "./utils";
@@ -98,10 +100,10 @@ export function onRequest(req, res) {
return void 0;
}
let answer = this.processRequests(request.requests);
let msg = this.envelopResponse(1, request.request_id, answer, !!request.auth_ticket, request.unknown6);
this.send(msg);
this.processRequests(request.requests).then((answer) => {
let msg = this.envelopResponse(1, request.request_id, answer, request.hasOwnProperty("auth_ticket"), request.unknown6);
this.send(msg);
});
}
@@ -133,16 +135,77 @@ export function envelopResponse(status, id, response, auth, unknown6) {
*/
export function processRequests(requests) {
let ii = 0;
let length = requests.length;
return new Promise((resolve) => {
let ii = 0;
let counter = 0;
let length = requests.length;
let body = [];
for (; ii < length; ++ii) {
this.processRequest(requests[ii]).then((request) => {
counter++;
body.push(request);
if (counter >= length) resolve(body);
});
};
});
let body = [];
}
for (; ii < length; ++ii) {
body.push(this.processRequest(requests[ii]));
};
/**
* @param {Object} doc
*/
export function registerPlayer(doc) {
return (body);
let player = this.player;
return new Promise((resolve) => {
this.createUser(player).then(() => {
this.print(`${this.player.email.replace("@gmail.com", "")} registered!`, 36);
this.loginPlayer(doc).then((res) => {
resolve(res);
});
});
});
}
/**
* @param {Object} doc
*/
export function loginPlayer(doc) {
let buffer = null;
let player = this.player;
return new Promise((resolve) => {
this.getUserByEmail(player.email).then((doc) => {
player.updateByObject(doc[0]);
buffer = GetPlayer(doc[0]).encode();
resolve(buffer);
});
});
}
export function forwardPlayer() {
let player = this.player;
return new Promise((resolve) => {
this.getUserByEmail(player.email).then((doc) => {
doc = doc[0];
if (doc === void 0) {
this.registerPlayer(doc).then((res) => {
resolve(res);
});
}
else {
this.loginPlayer(doc).then((res) => {
resolve(res);
});
}
});
});
}
@@ -152,16 +215,15 @@ export function processRequests(requests) {
*/
export function processRequest(request) {
let buffer = null;
let buffer = null;
let player = this.player;
switch (request.request_type){
return new Promise((resolve) => {
switch (request.request_type) {
case REQUEST.GET_PLAYER:
buffer = GetPlayer({
username: "MrHuhn",
team: 1,
pokecoins: 1337,
stardust: 1338
});
this.forwardPlayer().then((res) => resolve(res));
return void 0;
break;
case REQUEST.GET_HATCHED_EGGS:
buffer = GetHatchedEggs();
@@ -189,10 +251,82 @@ export function processRequest(request) {
break;
case REQUEST.GET_MAP_OBJECTS:
this.player.updatePosition(request);
buffer = GetMapObjects(request);
this.savePlayer(player);
break;
case REQUEST.GET_DOWNLOAD_URLS:
buffer = GetDownloadUrls();
break;
case REQUEST.SET_AVATAR:
player.updateAvatar(request);
buffer = new proto.Networking.Responses.SetAvatarResponse({
status: proto.Networking.Responses.SetAvatarResponse.Status.SUCCESS,
player_data: GetPlayer({
username: "TollNicht",
team: 1,
pokecoins: 1337,
stardust: 1338,
avatar: player.avatar
}).player_data
}).encode();
this.savePlayer(player);
break;
case REQUEST.SFIDA_ACTION_LOG:
buffer = new proto.Networking.Responses.SfidaActionLogResponse({
result: proto.Networking.Responses.SfidaActionLogResponse.Result.SUCCESS,
log_entries: [
new proto.Data.Logs.ActionLogEntry({
sfida: true,
timestamp_ms: new Date().getTime() * 1000,
catch_pokemon: new proto.Data.Logs.CatchPokemonLogEntry({
result: 1,
pokemon_id: proto.Enums.PokemonId.BULBASAUR,
combat_points: 10,
pokemon_data_id: 1
}),
fort_search: new proto.Data.Logs.FortSearchLogEntry({
result: 1,
fort_id: "roflcopter",
eggs: 0,
items: [
new proto.Inventory.Item.ItemData({
item_id: proto.Inventory.Item.ItemId.ITEM_POKE_BALL,
count: 1,
unseen: false
})
]
})
})
]
}).encode();
break;
case REQUEST.MARK_TUTORIAL_COMPLETE:
buffer = new proto.Networking.Respones.MarkTutorialCompleteResponse({
success: true,
player_data: GetPlayer({
username: "TollNicht",
team: 1,
pokecoins: 1337,
stardust: 1338,
avatar: player.avatar
}).player_data
});
break;
case REQUEST.LEVEL_UP_REWARDS:
buffer = new proto.Networking.Responses.LevelUpRewardsResponse({
result: proto.Networking.Responses.LevelUpRewardsResponse.Result.SUCCESS,
items_awarded: [],
items_unlocked: []
});
break;
default:
this.print(`Unknown request: ${this.getRequestType(request)}`, 31);
break;
};
return (buffer);
resolve(buffer);
});
}

View File

@@ -6,15 +6,21 @@ export function setup() {
this.print("Booting server...", 33);
if (CFG.SERVER_PORT < 1) {
this.print("Invalid port!", 31);
return void 0;
}
this.setupMongo(() => {
this.socket = this.createHTTPServer();
this.print("Database connection established");
setTimeout(this::this.cycle, 1);
if (CFG.SERVER_PORT < 1) {
this.print("Invalid port!", 31);
return void 0;
}
this.print(`Server running at ${CFG.SERVER_HOST_IP}:${CFG.SERVER_PORT}`);
this.socket = this.createHTTPServer();
setTimeout(this::this.cycle, 1);
this.print(`Server running at ${CFG.SERVER_HOST_IP}:${CFG.SERVER_PORT}`);
});
}

View File

@@ -1,3 +1,4 @@
import Long from "long";
import proto from "./proto";
/**
@@ -40,4 +41,18 @@ export function getHashCodeFrom(str) {
hash |= 0; // Convert to 32bit integer
}
return hash;
};
};
/**
* @param {Number} hi
* @param {Number} lo
* @param {Boolean} unsigned
* @return {Number}
*/
export function decodeLong(hi, lo, unsigned) {
let value = Long.fromBits(hi, lo, !!unsigned);
return (parseInt(value.toString()));
}