lib/steam-condenser/community/game_leaderboard.rb
# This code is free software; you can redistribute it and/or modify it under
# the terms of the new BSD License.
#
# Copyright (c) 2011-2015, Sebastian Staudt
require 'multi_xml'
require 'steam-condenser/community/uri'
require 'steam-condenser/community/game_leaderboard_entry'
require 'steam-condenser/community/steam_id'
require 'steam-condenser/community/xml_data'
module SteamCondenser::Community
# The GameLeaderboard class represents a single leaderboard for a specific
# game
#
# @author Sebastian Staudt
class GameLeaderboard
include XMLData
DISPLAY_TYPE_NONE = 0
DISPLAY_TYPE_NUMERIC = 1
DISPLAY_TYPE_SECONDS = 2
DISPLAY_TYPE_MILLISECONDS = 3
SORT_METHOD_NONE = 0
SORT_METHOD_ASC = 1
SORT_METHOD_DESC = 2
@@leaderboards = {}
# Returns the display type of the scores on this leaderboard
#
# @return [Fixnum] The display type of the scores
attr_reader :display_type
# Returns the number of entries on this leaderboard
#
# @return [Fixnum] The number of entries on this leaderboard
attr_reader :entry_count
# Returns the ID of the leaderboard
#
# @return [Fixnum] The ID of the leaderboard
attr_reader :id
# Returns the name of the leaderboard
#
# @return [String] The name of the leaderboard
attr_reader :name
# Returns the method that is used to sort the entries on the leaderboard
#
# @return [Fixnum] The sort method
attr_reader :sort_method
# Returns the leaderboard for the given game and leaderboard ID or name
#
# @param [Fixnum] app_id The application ID of the game
# @param [Fixnum, String] id The ID or name of the leaderboard to return
# @return [GameLeaderboard] The matching leaderboard if available
def self.leaderboard(app_id, id)
leaderboards = self.leaderboards app_id
if id.is_a? Fixnum
leaderboards[id]
else
leaderboards.each_value do |board|
return board if board.name == id
end
end
end
# Returns an array containing all of a game's leaderboards
#
# @param [Fixnum] app_id The application ID of the game
# @return [Array<GameLeaderboard>] The leaderboards for this game
def self.leaderboards(app_id)
self.load_leaderboards app_id unless @@leaderboards.key? app_id
@@leaderboards[app_id]
end
# Returns the entry on this leaderboard for the user with the given SteamID
#
# @param [Fixnum, SteamId] steam_id The 64bit SteamID or the `SteamId`
# object of the user
# @return [GameLeaderboardEntry] The entry of the user if available
# raise [SteamCondenserException] if an error occurs while fetching the
# leaderboard
def entry_for_steam_id(steam_id)
steam_id = steam_id.steam_id64 if steam_id.is_a? SteamId
parse "#@url&steamid=#{steam_id}"
error = @xml_data['error']
raise SteamCondenser::Error, error unless error.nil?
@xml_data['entries']['entry'].each do |entry_data|
if entry_data['steamid'].to_i == steam_id
return GameLeaderboardEntry.new entry_data, self
end
end
nil
end
# Returns an array of entries on this leaderboard for the user with the
# given SteamID and his/her friends
#
# @param [Fixnum, SteamId] steam_id The 64bit SteamID or the `SteamId`
# object of the user
# @return [Array<GameLeaderboardEntry>] The entries of the user and his/her
# friends
# raise [SteamCondenserException] if an error occurs while fetching the
# leaderboard
def entry_for_steam_id_friends(steam_id)
steam_id = steam_id.steam_id64 if steam_id.is_a? SteamId
parse "#@url&steamid=#{steam_id}"
error = @xml_data['error']
raise SteamCondenser::Error, error unless error.nil?
parse_entries
end
# Returns the entries on this leaderboard for a given rank range
#
# The range is inclusive and a maximum of 5001 entries can be returned in a
# single request.
#
# @param [Fixnum] first The first entry to return from the leaderboard
# @param [Fixnum] last The last entry to return from the leaderboard
# @return [Array<GameLeaderboardEntry>] The entries that match the given
# rank range
# raise [SteamCondenserException] if an error occurs while fetching the
# leaderboard
def entry_range(first, last)
if last < first
raise SteamCondenser::Error,
'First entry must be prior to last entry for leaderboard entry lookup.'
end
if (last - first) > 5000
raise SteamCondenser::Error,
'Leaderboard entry lookup is currently limited to a maximum of 5001 entries per request.'
end
parse "#@url&start=#{first}&end=#{last}"
error = @xml_data['error']
raise SteamCondenser::Error, error unless error.nil?
entries = []
@xml_data['entries']['entry'].each do |entry_data|
rank = entry_data['rank'].to_i
entries[rank] = GameLeaderboardEntry.new entry_data, self
end
parse_entries
end
private
# Creates a new leaderboard instance with the given XML data
#
# @param [Hash<String, Object>] board_data The XML data of the leaderboard
def initialize(board_data)
@url = board_data['url']
@id = board_data['lbid'].to_i
@name = board_data['name']
@entry_count = board_data['entries'].to_i
@sort_method = board_data['sortmethod'].to_i
@display_type = board_data['displaytype'].to_i
end
# Parses all entries available in the XML data
#
# @return [Array<GameLeaderboardEntry>] All available entries
def parse_entries
entries = []
@xml_data['entries']['entry'].each do |entry_data|
entries[entry_data['rank'].to_i] =
GameLeaderboardEntry.new entry_data, self
end
entries
end
# Loads the leaderboards of the specified games into the cache
#
# @param [Fixnum] app_id The application ID of the game
# @raise [SteamCondenserException] if an error occurs while fetching the
# leaderboards
def self.load_leaderboards(app_id)
begin
url = "http://steamcommunity.com/stats/#{app_id}/leaderboards/?xml=1"
boards_data = MultiXml.parse(URI.open(url, proxy: true)).values.first
rescue
raise SteamCondenser::Error.new 'XML data could not be parsed.', $!
end
error = boards_data['error']
raise SteamCondenser::Error, error unless error.nil?
@@leaderboards[app_id] = {}
boards_data['leaderboard'].each do |board_data|
leaderboard = GameLeaderboard.new board_data
@@leaderboards[app_id][leaderboard.id] = leaderboard
end
end
end
end