require 'pokeplot/helpers/math' require 'pokeplot/helpers/array' require 'pokeplot/api' module Pokeplot class Miner include Database attr_accessor :miner, :db def initialize(accounts, lat, lng, range = 20, interval = 600, pokemon = true, forts = true, threaded = false, encryption = '', log = true, apilog = true) @apis = [] @accounts = accounts @lat = lat @lng = lng @db = Database.mongo @range = range @interval = interval @pokemon = pokemon @forts = forts @threaded = threaded @encryption = encryption @logging = log @apilog = apilog @miner = nil @coords = [] get_all_coords end def start if !@miner.is_a?(Thread) @miner = Thread.new { puts "[+] Starting miner on new thread" if @logging puts "[+] #{@coords.count} coords to scan using #{@accounts.count} accounts" if @logging puts "[+] Logging in all accounts" if @logging if @threaded @threads = [] @accounts.each_with_index do |account, index| @threads << Thread.new do api = API.new(@lat, @lng, @encryption, @apilog) api.login(account['username'], account['password'], account['provider']) sleep(1) loop do current_time = Time.now.to_i groups = @coords.in_groups(@accounts.count) groups[index].each do |coord| api.set_location(coord[:lat], coord[:lng]) response = api.map_heartbeat parse_map_objects(response) sleep(10) end scan_time = Time.now.to_i - current_time puts "[+] Scan finnished for account #{account['username']} in #{scan_time} seconds" if @logging sleep_time = @interval - scan_time sleep_time = [sleep_time, 0].max puts "[+] Thread sleeping for #{sleep_time} seconds..." if @logging sleep(sleep_time) end end end else #NOT THEADED @accounts.each do |account| api = API.new(@lat, @lng, @encryption, @apilog) api.login(account['username'], account['password'], account['provider']) @apis.push(api) sleep(2) end loop do current_time = Time.now.to_i groups = @coords.in_groups(@apis.count) diff = groups.first.count - groups.last.count groups.last.push(*([0] * diff)) if diff > 0 groups = groups.transpose groups.each_with_index do |group, n| puts "[+] Starting group #{n + 1} of #{groups.count}" if @logging group_time = Time.now.to_i group.each_with_index do |coord, index| if coord.is_a?(Hash) api = @apis[index] api.set_location(coord[:lat], coord[:lng]) response = api.map_heartbeat parse_map_objects(response) end end group_time = Time.now.to_i - group_time puts "[+] Group finnished in #{group_time} seconds" if @logging end scan_time = Time.now.to_i - current_time puts "[+] Scan Time: #{scan_time} s'" if @logging sleep_time = @interval - scan_time sleep_time = [sleep_time, 0].max puts "[+] Sleeping for #{sleep_time} seconds..." if @logging sleep(sleep_time) end end } end end def stop Thread.kill(@miner) if @miner.is_a?(Thread) if @threads.is_a?(Array) @threads.each {|t| Thread.kill(t) if t.is_a?(Thread) } end @miner = nil end private def get_all_coords origin = {:lat => @lat, :lng => @lng} @coords = [origin] float_lat = @lat float_lng = @lng latrad = Helpers::Math.deg_to_rad(float_lat) hex_r = 70.0 #range of detection for pokemon = 100m || changed to 70 hex_m = 3.0**(0.5)/2.0*hex_r (1...(@range+1)).to_a.each do |a| (0...(a*6)).to_a.each do |i| x_un=1.5*hex_r/Helpers::Math.get_earth_radius(float_lat)/Math.cos(latrad)*180/Math::PI y_un=1.0*hex_m/Helpers::Math.get_earth_radius(float_lat)*180/Math::PI if i < a lat = float_lat+y_un*(-2*a+i) lng = float_lng+x_un*i elsif i < 2*a lat = float_lat+y_un*(-3*a+2*i) lng = float_lng+x_un*a elsif i < 3*a lat = float_lat+y_un*(-a+i) lng = float_lng+x_un*(3*a-i) elsif i < 4*a lat = float_lat+y_un*(5*a-i) lng = float_lng+x_un*(3*a-i) elsif i < 5*a lat = float_lat+y_un*(9*a-2*i) lng = float_lng+x_un*-a else lat = float_lat+y_un*(4*a-i) lng = float_lng+x_un*(-6*a+i) end @coords << {:lat => lat, :lng => lng} end end @coords end def parse_map_objects(response) if response[:GET_MAP_OBJECTS][:status] == :SUCCESS response[:GET_MAP_OBJECTS][:map_cells].each do |cell| cell[:wild_pokemons].each do |pokemon| if pokemon[:time_till_hidden_ms] < 0 puts "[+] Saving possible long spawn: #{pokemon[:spawn_point_id]}" if @logging longspawn(cell, pokemon) else if new_encounter?(pokemon[:encounter_id].to_s, pokemon[:spawn_point_id], pokemon[:latitude].to_s, pokemon[:longitude].to_s) && @pokemon @db[:encounters].insert_one({ cell_id: cell[:s2_cell_id].to_s, current_timestamp_ms: cell[:current_timestamp_ms].to_s, encounter_id: pokemon[:encounter_id].to_s, latitude: pokemon[:latitude].to_s, longitude: pokemon[:longitude].to_s, spawn_point_id: pokemon[:spawn_point_id], pokemon: pokemon[:pokemon_data][:pokemon_id].to_s, time_till_hidden_ms: pokemon[:time_till_hidden_ms].to_s }) puts "[+] Found a \e[36m#{pokemon[:pokemon_data][:pokemon_id]}\e[0m" if @logging end end end cell[:forts].each do |fort| if new_fort?(fort[:id].to_s) && @forts @db[:forts].insert_one({ cell_id: cell[:s2_cell_id].to_s, current_timestamp_ms: cell[:current_timestamp_ms].to_s, fort_id: fort[:id], enabled: fort[:enabled].to_s, latitude: fort[:latitude].to_s, longitude: fort[:longitude].to_s, type: fort[:type].to_s }) puts "[+] Found a fort: #{fort[:type]}" if @logging end end end else puts "[-] UNSUCCESSFUL RESPONSE STATUS #{response[:GET_MAP_OBJECTS][:status]}" if @logging end end def new_encounter?(encounter_id, spawn_point_id, lat, lng) if @db[:encounters].find({encounter_id: encounter_id, spawn_point_id: spawn_point_id, latitude: lat, longitude: lng}).count == 0 true else false end end def new_fort?(fort_id) if @db[:forts].find({fort_id: fort_id}).count == 0 true else false end end def longspawn(cell, pokemon) @db[:longspawn].insert_one({ cell_id: cell[:s2_cell_id].to_s, current_timestamp_ms: cell[:current_timestamp_ms].to_s, encounter_id: pokemon[:encounter_id].to_s, latitude: pokemon[:latitude].to_s, longitude: pokemon[:longitude].to_s, spawn_point_id: pokemon[:spawn_point_id], pokemon: pokemon[:pokemon_data][:pokemon_id].to_s, time_till_hidden_ms: pokemon[:time_till_hidden_ms].to_s }) puts "[+] Found a \e[36m#{pokemon[:pokemon_data][:pokemon_id]}\e[0m (Long spawn)" if @logging end end end