Browse Source

Update readme to be comprehensive. Close #1

Tweak objects and formatting.
master
Andrew Zah 3 years ago
parent
commit
6e055e7951
Signed by: andrei <zah@andrewzah.com> GPG Key ID: 0AE942445EB70FAA

+ 10
- 0
.travis.yml View File

@@ -1 +1,11 @@
language: crystal
script:
- crystal deps
- crystal spec
env:
global:
- ENCRYPTION_LABEL: 563f1b46fb00
- COMMIT_AUTHOR_EMAIL: zah.andrew@gmail.com
after_success:
- chmox a+x ./deploy.sh
- bash ./deploy.sh

+ 280
- 7
README.md View File

@@ -1,4 +1,4 @@
# dota
# dotacr

A Crystal client for the [DotA 2 API](https://wiki.teamfortress.com/wiki/WebAPI#Dota_2).

@@ -63,7 +63,7 @@ api.matches({"hero_id" => 43}) # Allowed options:
# :player_id - Integer, With this player (32-bit Steam ID)
# :league_id - Integer, In this league. Use Dota.leagues to get a list of leagues
# :mode_id - Integer, In this game mode. See Dota::API::Match::MODES
# :skill_level - Integer, In this skill level (ignored if :player_id is provided). See Dota::API::Match::SKILL_LEVELS
# :skill_level - Integer, In this skill level (ignored if :player_id is provided). See Dota::API::Match::SkillLevels
# :from - Integer, Minimum timestamp
# :to - Integer, Maximum timestamp
# :min_players - Integer, With at least this number of players
@@ -81,15 +81,288 @@ api.cosmetic_rarities # => All cosmetic rarities
api.friends(76561198052976237) # => All friends of user
```

TODO: Write usage instructions here
#### Custom Requests

## Development
For the unsupported endpoints, you can use `api.get`. For example, the following code is similar to `api.matches(789645621)` except it will return the raw JSON payload instead of an array of `Dota::Match`es.

TODO: Write development instructions here
```crystal
api.get(<Method>, <Class>, <Interface>, <Options Hash>)
api.get("GetMatchDetails", API::Match, "IDOTA2Match_570", {"match_id" => 789645621})
```

**Note**: For queries that return an array of objects, you must use the relative list class:
* Match => MatchesList
* BasicMatch => BasicMatchesList
* League => LeaguesList
* etc.

## API Objects

### Hero

```crystal
hero.id # Int8, ID of the hero
hero.name # String, Name of the hero
hero.image_url # String, URL of the hero portrait
```

### Item

```crystal
item.id # Int32
item.name # String
item.image_url # String
```

### Ability

```crystal
ability.id # Int32
ability.name # String -> "Beserker's Call"
ability.fullName # String -> "Axe Beserker's Call"
```

### Team
TeamsList:

```crystal
list.status # Int8
list.teams # Array(Dota::API::Team)
```

```crystal
team.player_ids # Array(Int32)
team.name # String
team.tag # String
team.country_code # String, ISO 3166-1 country code (see http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes)
team.admin_id # Integer, Team admin's 32-bit Steam ID
team.player_ids # Array[Integer], Players' 32-bit Steam IDs
team.logo # String, UGC ID of the team's logo
team.logo_sponsor # String, UGC ID of the team's logo
team.url # String, URL of the team's website
team.time_created # Int32
team.games_played # Int16
team.player0_id # Int32 | Nil
...
team.player6_id # Int32 | Nil
team.calibration_games_remaining # Int8
```

#### League
`LeaguesList` has one member: `leagues: Array(Dota::API::League)`.

```crystal
league.id # Int32
league.name # String
league.description # String
league.url # String
league.itemdef # Int32

Dota::API::League::Tiers
enum Tiers
Amateur = 1
Professional
Premier
end
```

#### Match

Caveat: Getting a list of matches via `api.matches` will call [GetMatchHistory](https://wiki.teamfortress.com/wiki/WebAPI/GetMatchHistory) which has very few attributes for the matches returned (obviously for performance reasons), as opposed to getting info about a particular match via `api.matches(id)` which will instead call [GetMatchDetails](https://wiki.teamfortress.com/wiki/WebAPI/GetMatchDetails). The former uses `Dota::API::BasicMatch`, the latter uses `Dota::API::Match`.

#### Dota::API::BasicMatch
The response will always be `Dota::API::BasicMatchesList`, even if there are 0 results.

```crystal
list.status # Int32
list.num_results # Int32
list.total_results # Int32
list.results_remaining # Int32
list.matches # Array(Dota::API::BasicMatch)
```

```crystal
basicMatch.match_id # Int64
basicmatch.match_seq_num # Int64
basicMatch.start_time # Int32
basicMatch.lobby_type # Dota::API::MatchStatus::GameModes
basicMatch.radiant_team_id # In32
basicMatch.dire_team_id # Int32
basicMatch.players # Array(Dota::API::BasicPlayer)
```

BasicPlayer:
```crystal
account_id # Int64 | Nil
player_slot # Int8
hero_id # Int32
```

#### Dota::API::Match
`Dota::API::MatchesList` has one member: `matches: Array(Dota::API::Match)`.

```crystal
match.id # Int64
match.radiant_win # Bool
match.duration # Int32, Length of the match, in seconds since the match began
match.pre_game_duration # Int32
match.start_time # Int32
match.match_seq_num # Int64
match.tower_status_radiant # Enum, Dota::API::MatchStatus::Towers
match.tower_status_dire # Enum, Dota::API::MatchStatus::Towers
match.barracks_status_radiant # Enum, Dota::API::MatchStatus::Barracks
match.barracks_status_dire # Enum, Dota::API::MatchStatus::Barracks
match.cluster # Int32
match.first_blood_time # Int32
match.lobby_type # Enum, Dota::API::MatchStatus::GameModes
match.human_players # Int8
match.leagueid # Int32
match.positive_votes # Int32
match.negative_votes # Int32
match.game_mode # Enum, Dota::API::MatchStatus::GameModes
match.flags # Int32
match.engine # Int32
match.radiant_score # Int32,
match.dire_score # Int32,
match.radiant_team_id # Int32 | Nil
match.radiant_name # String | Nil
match.radiant_logo # String | Nil
match.radiant_team_complete # Int32 | Nil
match.dire_team_id # Int32 | Nil
match.dire_name # String | Nil
match.dire_team_complete # Int32 | Nil
match.radiant_captain # Int32 | Nil
match.dire_captain # Int32 | Nil
match.picks_bans # Array(Dota::API::Match::Draft) | Nil, Picks and bans in the match, if the game mode is "Captains Mode"
match.players # Array(Dota::API::Match::Player) | Nil

# Dota::API::Match::Draft
draft.order # Integer, 1-20
draft.pick? # Boolean, true if the draft is a pick, and not a ban
draft.team # Enum, Dota::API::PlayerStatus::Teams
draft.hero_id # Int32

# Dota::API::Match::Player
player.account_id # Int64
player.player_slot # Int8
player.hero_id # Int8
player.kills # Int16
player.deaths # Int16
player.assists # Int16
player.leaver_status # Dota::API::PlayerStatus::Status
player.last_hits # Int16
player.denies # Int16
player.gold_per_min # Int16
player.xp_per_min # Int16
player.item0_id # Int16
player.item1_id # Int16
player.item2_id # Int16
player.item3_id # Int16
player.item4_id # Int16
player.item5_id # Int16
```

#### Live Matches
`Dota::API::LiveMatchesList` has one member: `liveMatches: Array(Dota::API::Match)`.

```crystal
live_match.radiant # Dota::API::LiveMatch::Side, Info about the team on the Radiant side
live_match.dire # Dota::API::LiveMatch::Side, Info about the team on the Dire side

live_match.id # Int64
live_match.lobby_id # Int64
live_match.spectators # Int32
live_match.league_id # Int32
live_match.stream_delay # Int32, Number of seconds the stream is behind actual game time
live_match.series_type # Int8, Best of X series
live_match.league_tier # Enum, Dota::API::League::Tiers
live_match.duration # Integer, Length of the match, in seconds since the match began
live_match.roshan_timer # Int16
live_match.scoreboard # Dota::API::LiveMatch::Scoreboard
live_match.players # Array(Dota::API::LiveMatch::SimplePlayer)
live_match.dire_team # Dota::API::LiveMatch::Team

SimplePlayer
sp.account_id # Int64
sp.name # String
sp.hero_id # Int32
sp.team # Enum, Dota::API::PlayerStatus::Teams

Team
t.name # String
t.id # Int64
t.logo # String
t.complete # Bool

Scoreboard
sb.duration # Float32
sb.roshan_respawn_timer # Int16
sb.radiant # Dota::API::LiveMatch::Side
sb.dire # Dota::API::LiveMatch::Side
```

### Side (Currently only used by LiveMatch)
```crystal
side.score # Int32
side.tower_state # Enum, Dota::API::MatchStatus::Towers
side.barracks_state # Enum, Dota::API::MatchStatus::Barracks
side.picks # Array(Pick) | Nil
side.bans # Array(Bans) | Nil
side.players # Array(LivePlayer)
side.abilities # Array(Ability) | Nil

Pick
pick.hero_id # Int32

Ban
ban.hero_id # Int32

Ability
ablity_id # Int32
ability_level # Int8

LivePlayer
lp.account_id # Int64
lp.player_slot # Int8
lp.level # Int8
lp.kills # Int16
lp.deaths # Int16
lp.assists # Int16
lp.denies # Int16
lp.gold # Int32
lp.gold_per_min # Int16
lp.xp_per_min # Int16
lp.ultimate_state # Int8
lp.ultimate_cooldown # Int32
lp.respawn_timer # Int32
lp.position_x # Float32
lp.position_y # Float32
lp.net_worth # Int32
lp.item0_id # Int16
...
lp.item5_id # Int16
```

### Friends
`Dota::API::FriendsList` has one member: `friends: Array(Dota::API::Friend)`.

```crystal
friend.steamid # String
friend.relationship # String
friend.friend_since # Int32
```

## Resources

- [vinnicc/dota](https://github.com/vinnicc/dota) The ruby version of this wrapper, and the inspiration behind it.
- [Steam-Powered DOTA on Rails](http://www.sitepoint.com/steam-powered-dota-on-rails/) and [DOTA 2 on Rails: Digging Deeper](http://www.sitepoint.com/dota-2-rails-digging-deeper/) by Ilya Bodrov-Krukowski - A tutorial for getting personal match statistics that makes use of this library for Steam integration. (www.sitepoint.com)
- [Things You Should Know Before Starting API Development](http://dev.dota2.com/showthread.php?t=58317) by MuppetMaster42 (dev.dota2.com)
- [Dota 2 WebAPI Wiki](https://wiki.teamfortress.com/wiki/WebAPI#Dota_2) (wiki.teamfortress.com)
- [Dota 2 WebAPI Forums](http://dev.dota2.com/forumdisplay.php?f=411) (dev.dota2.com)

## Contributing

1. Fork it ( https://github.com/[your-github-name]/dota/fork )
1. Fork it ( https://github.com/azah/dotacr/fork )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
@@ -97,4 +370,4 @@ TODO: Write development instructions here

## Contributors

- [[your-github-name]](https://github.com/[your-github-name]) Andrew Zah - creator, maintainer
- [azah](https://github.com/azah) Andrew Zah - creator, maintainer

+ 66
- 0
deploy.sh View File

@@ -0,0 +1,66 @@
#!/bin/bash

# Script adapted from https://gist.github.com/domenic/ec8b0fc8ab45f39403dd
set -e # Exit with nonzero exit code if anything fails

# Save some useful information
REPO=`git config remote.origin.url`
SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:}
SHA=`git rev-parse --verify HEAD`

SOURCE_BRANCH="master"
TARGET_BRANCH="gh-pages"

function doCompile {
crystal doc
}

# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then
echo "Skipping deploy; just doing a build."
doCompile
exit 0
fi

if [ -n "$TRAVIS_TAG" ]; then
SOURCE_BRANCH=$TRAVIS_TAG
fi

# Clone the existing gh-pages for this repo into out/
# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply)
git clone -b $TARGET_BRANCH $REPO out

mkdir -p out/doc/$SOURCE_BRANCH

# Clean out existing contents
rm -rf out/doc/$SOURCE_BRANCH/**/* || exit 0

# Run our compile script
doCompile

# Move results
mv doc/* out/doc/$SOURCE_BRANCH/

# Now let's go have some fun with the cloned repo
cd out

git config user.name "Travis CI"
git config user.email "$COMMIT_AUTHOR_EMAIL"

# Commit the "changes", i.e. the new version.
# The delta will show diffs between new and old versions.
git add .
git commit -m "Deploy to GitHub Pages: ${SHA}"

# Get the deploy key by using Travis's stored variables to decrypt deploy_key.enc
ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"
ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR}
ENCRYPTED_IV=${!ENCRYPTED_IV_VAR}
openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy_key.enc -out deploy_key -d
chmod 600 deploy_key
eval `ssh-agent -s`
ssh-add deploy_key

# Now that we're all set up, we can push.
git push $SSH_REPO $TARGET_BRANCH

BIN
deploy_key.enc View File


+ 2
- 2
spec/dota_spec.cr View File

@@ -13,9 +13,9 @@ describe Dota do
Dota::Dota.configuration.api_key.should eq "xx"
end

# set up api
# Set up API with Travis env vars
Dota::Dota.configure do |config|
config.api_key = "xx"
config.api_key = ENV["api_key"]
end
api = Dota::Dota.api


+ 1
- 1
src/dota/api/client.cr View File

@@ -84,7 +84,7 @@ module Dota

def live_matches(options = {} of String => Int32 | String)
response = get("GetLiveLeagueGames", LiveMatchesList, "IDOTA2Match_570", options)
response.games if response.games.size > 0
response.liveMatches if response.liveMatches.size > 0
end

def cosmetic_rarities(options = {"language" => "en"})

+ 11
- 0
src/dota/api/converters.cr View File

@@ -0,0 +1,11 @@
module Dota
module API
module Converters
module LogoConverter
def self.from_json(parser : JSON::PullParser) : String
parser.read_raw.to_s
end
end
end
end
end

+ 4
- 4
src/dota/api/league.cr View File

@@ -17,15 +17,15 @@ module Dota
itemdef: Int32
)

def id
@leagueid
end

enum Tiers
Amateur = 1
Professional
Premier
end

def to_s
"League: #{@name}"
end
end
end
end

+ 35
- 18
src/dota/api/live_match.cr View File

@@ -2,7 +2,7 @@ module Dota
module API
class LiveMatchesList
JSON.mapping(
games: Array(LiveMatch)
liveMatches: {key: "games", type: Array(LiveMatch)}
)
end

@@ -18,16 +18,24 @@ module Dota
stream_delay_s: Int32,
radiant_series_wins: Int32,
dire_series_wins: Int32,
series_type: Int32,
series_type: Int8,
league_series_id: Int32,
league_game_id: Int32,
stage_name: String,
league_tier: Int32,
league_tier: League::Tiers,
dire_team: {type: Team, nilable: true},
radiant_team: {type: Team, nilable: true},
scoreboard: {type: Scoreboard, nilable: true}
)

def id
@match_id
end

def roshan_timer
@scoreboard["roshan_respawn_timer"]
end

class SimplePlayer
include Dota::API::PlayerStatus
JSON.mapping(
@@ -39,10 +47,12 @@ module Dota
end

class Team
include Dota::API::Converters

JSON.mapping(
team_name: String,
team_id: Int32,
team_logo: Int32,
name: {key: "team_name", type: String},
id: {key: "team_id", type: Int64},
logo: {key: "team_logo", type: String, converter: LogoConverter},
complete: Bool
)
end
@@ -50,7 +60,7 @@ module Dota
class Scoreboard
JSON.mapping(
duration: Float32,
roshan_respawn_timer: Int32,
roshan_respawn_timer: Int16,
radiant: Side,
dire: Side
)
@@ -70,7 +80,7 @@ module Dota
class Ability
JSON.mapping(
ability_id: Int32,
ability_level: Int32
ability_level: Int8
)
end

@@ -80,24 +90,24 @@ module Dota
barracks_state: Barracks,
picks: {type: Array(Pick), nilable: true},
bans: {type: Array(Ban), nilable: true},
players: Array(ComplexPlayer),
players: Array(LivePlayer),
abilities: {type: Array(Ability), nilable: true}
)
end

class ComplexPlayer
class LivePlayer
JSON.mapping(
account_id: Int32,
account_id: Int64,
player_slot: Int32,
hero_id: Int32,
level: Int32,
kills: Int32,
death: Int32,
assists: Int32,
last_hits: Int32,
denies: Int32,
level: Int8,
kills: Int16,
deaths: {key: "death", type: Int16},
assists: Int16,
last_hits: Int16,
denies: Int16,
gold: Int32,
gold_per_min: Int32,
gold_per_min: Int16,
xp_per_min: Int32,
ultimate_state: Int32,
ultimate_cooldown: Int32,
@@ -112,6 +122,13 @@ module Dota
item4_id: {type: Int16, key: "item4"},
item5_id: {type: Int16, key: "item5"}
)

def items
[
item0_id, item1_id, item2_id,
item3_id, item4_id, item5_id,
].map { |id| Item.new(id.to_i32) }
end
end
end
end

+ 6
- 7
src/dota/api/match.cr View File

@@ -3,12 +3,7 @@ module Dota
class Match
include Dota::API::MatchStatus
include Dota::API::PlayerStatus

module LogoConverter
def self.from_json(parser : JSON::PullParser) : String
parser.read_raw.to_s
end
end
include Dota::API::Converters

JSON.mapping(
match_id: Int64,
@@ -47,12 +42,16 @@ module Dota
players: {type: Array(Player), nilable: true}
)

def id
@match_id
end

class Draft
JSON.mapping(
is_pick: Bool,
hero_id: Int32,
team: Teams,
order: Int32
order: Int8
)
end


+ 1
- 1
src/dota/api/status/match_status.cr View File

@@ -81,4 +81,4 @@ module Dota
end
end
end
end
end

+ 1
- 1
src/dota/api/status/player_status.cr View File

@@ -19,4 +19,4 @@ module Dota
end
end
end
end
end

+ 20
- 10
src/dota/api/team.cr View File

@@ -8,25 +8,35 @@ module Dota
end

class Team
include Dota::API::Converters

JSON.mapping(
name: String,
tag: String,
time_created: Int32,
calibration_games_remaining: Int8,
logo: Int64,
logo_sponsor: Int64,
logo: {type: String, converter: LogoConverter},
logo_sponsor: {type: String, converter: LogoConverter},
country_code: String,
url: String,
games_played: Int16,
admin_account_id: Int32,
player_0_account_id: {type: Int32, nilable: true},
player_1_account_id: {type: Int32, nilable: true},
player_2_account_id: {type: Int32, nilable: true},
player_3_account_id: {type: Int32, nilable: true},
player_4_account_id: {type: Int32, nilable: true},
player_5_account_id: {type: Int32, nilable: true},
player_6_account_id: {type: Int32, nilable: true}
admin_id: {key: "admin_account_id", type: Int32},
player0_id: {key: "player_0_account_id", type: Int32, nilable: true},
player1_id: {key: "player_1_account_id", type: Int32, nilable: true},
player2_id: {key: "player_2_account_id", type: Int32, nilable: true},
player3_id: {key: "player_3_account_id", type: Int32, nilable: true},
player4_id: {key: "player_4_account_id", type: Int32, nilable: true},
player5_id: {key: "player_5_account_id", type: Int32, nilable: true},
player6_id: {key: "player_6_account_id", type: Int32, nilable: true},
)

def player_ids
[
player_0_account_id, player_1_account_id, player_2_account_id,
player_3_account_id, player_4_account_id, player_5_account_id,
player_6_account_id,
].compact_map &.itself
end
end
end
end

+ 1
- 1
src/dota/configuration.cr View File

@@ -1,7 +1,7 @@
module Dota
class Configuration
property api_key : String?
getter api_version : String
property api_version : String

DEFAULT_API_VERSION = "v1"
OPTIONS = [API_KEY, API_VERSION]

+ 1
- 1
src/dota/utils/mapped.cr View File

@@ -17,4 +17,4 @@ module Dota
end
end
end
end
end

Loading…
Cancel
Save