diff --git a/.gitignore b/.gitignore index 7e1c71f3..2c1aca37 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +examples/config.js +examples/sentry test/config.js test/sentry node_modules diff --git a/.travis.yml b/.travis.yml index 1f6ff9f8..122f46c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: - - "6.2.0" + - "6.2.1" - "4.4.5" diff --git a/README.md b/README.md index 8f41c996..a7a1e2b6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ node-dota2 A node-steam plugin for Dota 2, consider it in alpha state. Check out my blog post (my only blog post), [Extending node-dota2](https://blog.rjackson.me/extending-node-dota2/), for a rough overview of adding new functionality to the library. +A fair warning, while the way you search for new functionality is still the same, quite a lot has changed (and been simplified) implementation wise. +It is now easier to implement new functionality than it was back when this blog was written. ## Upgrade guide @@ -21,20 +23,37 @@ A few backwards incompatible API changes were included with version 4.0.0. * `requestTeamIDByName` * `requestTeamMemberProfile` * The `teamData` event now throws an extra parameter `league_id` +* The `matchMakingStatsData` event's first two parameters changed as the old values no longer exist. +* The `matchMinimalDetailsData` event now returns the `last_match` bool as first argument. +## Installation and setup +* `npm install steam; npm install` in the repository root (install Steam first to work around a node-steam#222) +* Copy `config.js.example` to `config.js` and edit appropriately +* Run the example script: `node example.js` +* If you receive Error 63 you need to provide a Steam Guard code by setting the Steam Guard code in `config.js` and launching again. +* Make sure to use at least version 4.4.5 of node js ## Initializing Parameters: * `steamClient` - Pass a SteamClient instance to use to send & receive GC messages. * `debug` - A boolean noting whether to print information about operations to console. +* `debugMore` - A boolean noting whether to print extended debug information. Activating this will log messages for each proto message exchanged with the GC. ```js var Steam = require('steam'), steamClient = new Steam.SteamClient(), dota2 = require('dota2'), - Dota2 = new dota2.Dota2Client(steamClient, true); + Dota2 = new dota2.Dota2Client(steamClient, true, false); ``` +## Examples +The `examples` directory contains two Dota2 bots as an example. One contains commented-out dota2 methods, the other has boolean activated methods. +Both examples show how to interact with the library. + +## Testing +There is a partial automated test suite for node-dota2, which is located in the test directory. +You need to configure the `STEAM_USERNAME` and `STEAM_PASSWORD` environment variables to be able to run it. +You can launch the tests by running the file with mocha. ##Properties ###AccountID @@ -170,22 +189,30 @@ Requests the authenticated user's team data. Requests the profile for a given team. +**Warning** protobuf no longer exists, function is now deprecated. + #### requestTeamMemberProfile(steam_id, [callback]) - DEPRECATED * `steam_id` - Steam ID of the user whose team profile you want * `[callback]` - optional callback, returns args: `err, response`. Requests the profile of the team a given user belongs to. +**Warning** protobuf no longer exists, function is now deprecated. + #### requestTeamIDByName(team_name, [callback]) - DEPRECATED * `team_name` - Name of a team * `[callback]` - optional callback, returns args: `err, response`. Requests the ID for a given team name. -#### requestProTeamList([callback]) +**Warning** protobuf no longer exists, function is now deprecated. + +#### requestProTeamList([callback]) - STATUS UNKNOWN * `[callback]` - optional callback, returns args: `err, response`. -Requests the list of pro teams +Requests the list of pro teams. + +**Warning** this request no longer triggers a response from the GC. This might be temporary. ### Community #### requestPlayerMatchHistory(account_id, [options], [callback]) @@ -208,7 +235,7 @@ Provide a callback or listen for the `playerMatchHistoryData` for the GC's respo Sends a message to the Game Coordinator requesting `account_id`'s profile data. Provide a callback or listen for `profileData` event for Game Coordinator's response. Requires the GC to be ready (listen for the `ready` event before calling). -**This functionality is currently disabled by Valve** +**Warning** Valve's privacy policy has become stricter since reborn. This function is now reserved for internal use. #### requestProfileCard (account_id, [callback]) * `account_id` - Account ID (lower 32-bits of a 64-bit Steam ID) of the user whose profile card you wish to view. @@ -273,8 +300,6 @@ Note: There is a server-side rate-limit of 100 requests per 24 hours on this me Sends a message to the Game Coordinator requesting the match details for matches corresponding to `match_ids`. Provide a callback or listen for `matchMinimalDetailsData` event for Game Coordinator's response. Requires the GC to be ready (listen for the `ready` event before calling). -Note: `jimmydorry` was lazy when implementing this, so the `match_ids` variable only accepts a single matchID right now. It was only implemented to prove that it was leaking data for anonymous users. Someone that wants to use this method should go fixup the copy-paste job, to make it more useful. - #### requestMatchmakingStats() Sends a message to the Game Coordinator requesting some matchmaking stats. Listen for the `matchmakingStatsData` event for the Game Coordinator's response (cannot take a callback because of Steam's backend, or RJackson's incompetence; not sure which). Requires the GC to be ready (listen for the `ready` event before calling). @@ -345,9 +370,9 @@ Sends a message to the Game Coordinator requesting to join a lobby. Provide a c * `series_type`: Use the series type enum. * `radiant_series_wins`: # of games won so far, e.g. for a Bo3 or Bo5. * `dire_series_wins`: # of games won so far, e.g. for a Bo3 or Bo5. - * `allchat`: Enable all chat? + * `allchat`: Enable all chat for VOIP * `league_id`: The league this lobby is being created for. Optional - * `dota_tv_delay`: TODO. + * `dota_tv_delay`: Number of seconds the game should be delayed for DotaTV. * `custom_game_mode`: TODO. * `custom_map_name`: TODO. * `custom_difficulty`: TODO. @@ -675,17 +700,17 @@ Emitted when GC responds to the `requestmatchDetails` method. See the [protobuf schema](https://github.com/SteamRE/SteamKit/blob/master/Resources/Protobufs/dota/dota_gcmessages_client.proto#L1571) for `matchDetailsData`'s object structure. -### `matchMinimalDetailsData` (`match_id`, `matchMinimalDetailsData`) -* `match_id` - Match ID whom the data is associatd with. +### `matchMinimalDetailsData` (`matchMinimalDetailsData`) +* `last_match` - Bool, usage unknown * `matchMinimalDetailsData` - The raw match details data object. Emitted when GC responds to the `requestMatchMinimalDetails` method. See the [protobuf schema](https://github.com/SteamRE/SteamKit/blob/5acc8bb72bb7fb79ad08723a431fcbfe90669230/Resources/Protobufs/dota/dota_gcmessages_client.proto#L621-L650) for `matchMinimalDetailsData`'s object structure. -### `matchmakingStatsData` (`searchingPlayersByGroup`, `disabledGroups`, `matchmakingStatsResponse`) -* `searchingPlayersByGroup` - Current players searching for matches per group. -* `disabledGroups` - Bitmask corresponding to groups in `searchingPlayersByGroup`. Groups marked as disabled will have a value of 0. +### `matchmakingStatsData` (`matchgroups_version`, `match_groups`, `matchmakingStatsResponse`) +* `matchgroups_version` - Version of the current list of match groups. +* `match_groups` - Array of CMsgMatchmakingMatchGroupInfo objects. Contains info on the number of people searching and ping penalty. * `matchmakingStatsResponse` - Raw response object. Emitted when te GC response to the `requestMatchmakingStats` method. The array order dictates which matchmaking groups the figure belongs to. @@ -924,14 +949,5 @@ Use this to pass valid server region data to `createPracticeLobby`. Use this to pass valid game mode data to `createPracticeLobby`. -## Testing -There is no automated test suite for node-dota2 (I've no idea how I'd make one for the stuff this does :o), however there the `test` directory does contain a Steam bot with commented-out dota2 methods; you can use this bot to test the library. - -### Setting up -* `npm install steam; npm install` in the repository root (install Steam first to work around a node-steam#222) -* Copy `config.js.example` to `config.js` and edit appropriately -* Run the test script: `node test.js` -* If you receive Error 63 you need to provide a Steam Guard code by setting the Steam Guard code in `config.js` and launching again. -* Make sure to use at least version 0.12 of node js diff --git a/examples/example2.js b/examples/example2.js index 972cb7ba..43cb876f 100644 --- a/examples/example2.js +++ b/examples/example2.js @@ -2,7 +2,7 @@ var steam = require("steam"), util = require("util"), fs = require("fs"), crypto = require("crypto"), - dota2 = require("./"), + dota2 = require("../"), steamClient = new steam.SteamClient(), steamUser = new steam.SteamUser(steamClient), steamFriends = new steam.SteamFriends(steamClient), @@ -89,9 +89,22 @@ var onSteamLogOn = function onSteamLogOn(logonResp) { if(creatingLobby == 1){ // sets only password, nothing more var lobbyPassword = "ap"; - var lobbyName = "Lobby Name"; - - Dota2.createPracticeLobby(lobbyPassword, lobbyName, function(err, data){ + var properties = { + "game_name": "MyLobby", + "server_region": 3, + "game_mode": 2, + "series_type": 2, + "game_version": 1, + "allow_cheats": false, + "fill_with_bots": false, + "allow_spectating": true, + "pass_key": lobbyPassword, + "radiant_series_wins": 0, + "dire_series_wins": 0, + "allchat": true + } + + Dota2.createPracticeLobby(lobbyPassword, properties, function(err, data){ // util.log(JSON.stringify(data)); }); } @@ -116,6 +129,19 @@ var onSteamLogOn = function onSteamLogOn(logonResp) { }); } + // ---------------------------------- + + // SOURCETV + + var sourceGames = 0; + + if (sourceGames == 1) { + Dota2.requestSourceTVGames(); + Dota2.on('sourceTVGamesData', (gamesData) => { + util.log(gamesData); + }); + } + }); Dota2.on("unready", function onUnready() { @@ -143,16 +169,18 @@ onSteamError = function onSteamError(error) { }; steamUser.on('updateMachineAuth', function(sentry, callback) { - fs.writeFileSync('sentry', sentry.bytes) + var hashedSentry = crypto.createHash('sha1').update(sentry.bytes).digest(); + fs.writeFileSync('sentry', hashedSentry) util.log("sentryfile saved"); - callback({ sha_file: crypto.createHash('sha1').update(sentry.bytes).digest() }); + callback({ sha_file: hashedSentry}); }); var logOnDetails = { "account_name": global.config.steam_user, "password": global.config.steam_pass, }; +if (global.config.steam_guard_code) logOnDetails.auth_code = global.config.steam_guard_code; try { var sentry = fs.readFileSync('sentry'); @@ -171,4 +199,4 @@ steamClient.on('connected', function() { steamClient.on('logOnResponse', onSteamLogOn); steamClient.on('loggedOff', onSteamLogOff); steamClient.on('error', onSteamError); -steamClient.on('servers', onSteamServers); \ No newline at end of file +steamClient.on('servers', onSteamServers); diff --git a/handlers/chat.js b/handlers/chat.js index 277b71dd..6b7fdf07 100644 --- a/handlers/chat.js +++ b/handlers/chat.js @@ -192,7 +192,13 @@ var onOtherLeftChannel = function onOtherLeftChannel(message) { var channel = this._getChannelById(otherLeft.channel_id); // Check if it is me that left the channel if ("" + otherLeft.steam_id === "" + this._client.steamID) { - if (this.debug) util.log("Left channel " + channel.channel_name); + if (this.debug) { + if (channel) { + util.log("Left channel " + channel.channel_name); + } else { + util.log("This probably should be physically impossible, but whatever: you managed to leave a channel you didn't know you were in, congratulations..."); + } + } this.emit("chatLeave", channel.channel_name, otherLeft.steam_id, @@ -202,7 +208,13 @@ var onOtherLeftChannel = function onOtherLeftChannel(message) { if ("" + item.channel_id == "" + channel.channel_id) return false; }); } else { - if (this.debug) util.log(otherLeft.steam_id + " left channel " + channel.channel_name); + if (this.debug) { + if (channel) { + util.log(otherLeft.steam_id + " left channel " + channel.channel_name); + } else { + util.log(otherLeft.steam_id + " left channel " + otherLeft.channel_id + " (PS: why do I get messages from a chat I don't know? Did you kill me D: ?)"); + } + } this.emit("chatLeave", channel.channel_name, otherLeft.steam_id, diff --git a/handlers/community.js b/handlers/community.js index 560da5d2..83e9b16a 100644 --- a/handlers/community.js +++ b/handlers/community.js @@ -26,22 +26,22 @@ Dota2.Dota2Client.prototype.requestPlayerMatchHistory = function(account_id, opt onPlayerMatchHistoryResponse, callback); }; -Dota2.Dota2Client.prototype.requestProfile = function(account_id, request_name, callback) { - callback = callback || null; - var _self = this; +// Dota2.Dota2Client.prototype.requestProfile = function(account_id, request_name, callback) { +// callback = callback || null; +// var _self = this; - /* Sends a message to the Game Coordinator requesting `accountId`'s profile data. Listen for `profileData` event for Game Coordinator's response. */ - if (this.debug) util.log("Sending profile request"); +// /* Sends a message to the Game Coordinator requesting `accountId`'s profile data. Listen for `profileData` event for Game Coordinator's response. */ +// if (this.debug) util.log("Sending profile request"); - var payload = new Dota2.schema.CMsgDOTAProfileRequest({ - "account_id": account_id, - "request_name": request_name, - "engine": 1 - }); - this.sendToGC( Dota2.schema.EDOTAGCMsg.k_EMsgGCProfileRequest, - payload, - onProfileResponse, callback); -}; +// var payload = new Dota2.schema.CMsgDOTAProfileRequest({ +// "account_id": account_id, +// "request_name": request_name, +// "engine": 1 +// }); +// this.sendToGC( Dota2.schema.EDOTAGCMsg.k_EMsgGCProfileRequest, +// payload, +// onProfileResponse, callback); +// }; Dota2.Dota2Client.prototype.requestProfileCard = function(account_id, callback) { callback = callback || null; diff --git a/handlers/match.js b/handlers/match.js index 5adfc019..5aeef1db 100644 --- a/handlers/match.js +++ b/handlers/match.js @@ -131,7 +131,7 @@ var onMatchMinimalDetailsResponse = function onMatchMinimalDetailsResponse(messa /*if (this.debug)*/ util.log("Received match minimal data for: " + matchMinimalDetailsResponse.matches.match_id); this.emit("matchMinimalDetailsData", - matchMinimalDetailsResponse.matches.match_id, + matchMinimalDetailsResponse.last_match, matchMinimalDetailsResponse); if (callback) callback(null, matchMinimalDetailsResponse); } else { @@ -142,14 +142,15 @@ var onMatchMinimalDetailsResponse = function onMatchMinimalDetailsResponse(messa }; handlers[Dota2.schema.EDOTAGCMsg.k_EMsgClientToGCMatchesMinimalResponse] = onMatchMinimalDetailsResponse; +// TODO: replace first two parameters by matchmakingStatsResponse.match_groups var onMatchmakingStatsResponse = function onMatchmakingStatsResponse(message) { // Is not Job ID based - can't do callbacks. var matchmakingStatsResponse = Dota2.schema.CMsgDOTAMatchmakingStatsResponse.decode(message); if (this.debug) util.log("Received matchmaking stats"); this.emit("matchmakingStatsData", - matchmakingStatsResponse.searching_players_by_group_source2, - matchmakingStatsResponse.disabled_groups_source2, + matchmakingStatsResponse.matchgroups_version, + matchmakingStatsResponse.match_groups, matchmakingStatsResponse); }; handlers[Dota2.schema.EDOTAGCMsg.k_EMsgGCMatchmakingStatsResponse] = onMatchmakingStatsResponse; diff --git a/handlers/team.js b/handlers/team.js index 4ad7d4c6..5f6a919e 100644 --- a/handlers/team.js +++ b/handlers/team.js @@ -60,6 +60,8 @@ Dota2.Dota2Client.prototype.requestTeamMemberProfile = function requestTeamMembe onTeamProfileResponse, callback); } */ + +// No longer gets a response from the GC Dota2.Dota2Client.prototype.requestProTeamList = function requestProTeamList(callback) { // Request the list of pro teams callback = callback || null; @@ -115,6 +117,7 @@ var onTeamIDByNameResponse = function onTeamIDByNameResponse(message, callback) }; handlers[Dota2.schema.EDOTAGCMsg.k_EMsgGCTeamIDByNameResponse] = onTeamIDByNameResponse;*/ +// No longer gets triggered var onProTeamListResponse = function onProTeamListResponse(message, callback) { var teams = Dota2.schema.CMsgDOTAProTeamListResponse.decode(message); diff --git a/package.json b/package.json index 07fa63ea..fb5c72f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dota2", - "version": "4.0.0", + "version": "4.0.1", "dependencies": { "bignumber.js": "^2.1.0", "deferred": "^0.7.2", diff --git a/proto/dota_client_enums.proto b/proto/dota_client_enums.proto index 418feafc..f68e757d 100644 --- a/proto/dota_client_enums.proto +++ b/proto/dota_client_enums.proto @@ -25,7 +25,6 @@ enum ETournamentTeamState { k_ETournamentTeamState_NodeMax = 1024; k_ETournamentTeamState_Eliminated = 14003; k_ETournamentTeamState_Forfeited = 14004; - k_ETournamentTeamState_Refunded = 14005; k_ETournamentTeamState_Finished1st = 15001; k_ETournamentTeamState_Finished2nd = 15002; k_ETournamentTeamState_Finished3rd = 15003; @@ -68,8 +67,10 @@ enum ETournamentNodeState { k_ETournamentNodeState_A_WonByForfeit = 7; k_ETournamentNodeState_B_WonByForfeit = 8; k_ETournamentNodeState_A_Bye = 9; - k_ETournamentNodeState_A_Forfeit = 10; + k_ETournamentNodeState_A_Abandoned = 10; k_ETournamentNodeState_ServerFailure = 11; + k_ETournamentNodeState_A_TimeoutForfeit = 12; + k_ETournamentNodeState_A_TimeoutRefund = 13; } enum EDOTAGroupMergeResult { diff --git a/proto/dota_gcmessages_client.proto b/proto/dota_gcmessages_client.proto index 408260f4..fc30cd9d 100644 --- a/proto/dota_gcmessages_client.proto +++ b/proto/dota_gcmessages_client.proto @@ -145,6 +145,7 @@ message CMsgDOTAPopup { TOURNAMENT_GAME_HAS_NO_DIRE_TEAM = 25; TOURNAMENT_GAME_SQL_UPDATE_FAILED = 26; NOT_LEAGUE_ADMIN = 27; + IN_ANOTHER_GAME = 29; PARTY_MEMBER_IN_ANOTHER_GAME = 30; PARTY_MEMBER_IN_LOW_PRIORITY = 31; CLIENT_OUT_OF_DATE = 32; @@ -222,8 +223,8 @@ message CMsgDOTASubmitLobbyMVPVoteResponse { message CMsgDOTALobbyMVPNotifyRecipient { optional uint32 voter_account_id = 1; - optional uint32 num_votes = 2; - optional string voter_persona_name = 3; + optional uint32 recipient_account_id = 2; + optional uint32 num_votes = 3; } message CMsgDOTALobbyMVPAwarded { @@ -597,6 +598,14 @@ message CMsgDOTAMatchmakingStatsResponse { repeated .CMsgMatchmakingMatchGroupInfo match_groups = 8; } +message CMsgDOTAUpdateMatchmakingStats { + optional .CMsgDOTAMatchmakingStatsResponse stats = 1; +} + +message CMsgDOTAUpdateMatchManagementStats { + optional .CMsgDOTAMatchmakingStatsResponse stats = 1; +} + message CMsgDOTASetMatchHistoryAccess { optional bool allow_3rd_party_match_history = 1; } @@ -899,6 +908,13 @@ message CMsgDOTAGetPlayerMatchHistoryResponse { optional uint32 engine = 12; optional bool active_battle_pass = 13; optional bool seasonal_rank = 14; + optional uint32 tourney_id = 15; + optional uint32 tourney_round = 16; + optional uint32 tourney_tier = 17; + optional uint32 tourney_division = 18; + optional uint32 team_id = 19; + optional string team_name = 20; + optional uint64 ugc_team_ui_logo = 21; } repeated .CMsgDOTAGetPlayerMatchHistoryResponse.Match matches = 1; @@ -1277,8 +1293,9 @@ message CMsgDOTAPartyRichPresence { optional uint32 skill_level = 2; optional uint32 round = 3; optional uint32 tournament_id = 4; - optional .EWeekendTourneyRichPresenceEvent event = 5 [default = k_EWeekendTourneyRichPresenceEvent_None]; - optional uint32 event_round = 6; + optional uint32 state_seq_num = 5; + optional .EWeekendTourneyRichPresenceEvent event = 6 [default = k_EWeekendTourneyRichPresenceEvent_None]; + optional uint32 event_round = 7; } optional fixed64 party_id = 1; @@ -1662,6 +1679,14 @@ message CMsgClientToGCRequestEventPointLogResponse { optional bool community_goal_item = 1; } + message CorrectPredictionEvent { + optional uint32 prediction_id = 1; + } + + message InGamePredictionCorrectEvent { + optional uint64 match_id = 1; + } + message EventPointTransaction { optional uint32 time = 1; optional int32 event_points = 2; @@ -1674,6 +1699,8 @@ message CMsgClientToGCRequestEventPointLogResponse { optional .CMsgClientToGCRequestEventPointLogResponse.TipReceivedEvent tip_received_event = 9; optional .CMsgClientToGCRequestEventPointLogResponse.RecycledItemEvent recycled_item_event = 10; optional .CMsgClientToGCRequestEventPointLogResponse.AchievementEvent achievement_event = 11; + optional .CMsgClientToGCRequestEventPointLogResponse.InGamePredictionCorrectEvent in_game_prediction_event = 12; + optional .CMsgClientToGCRequestEventPointLogResponse.CorrectPredictionEvent prediction_event = 13; } optional bool result = 1; @@ -1804,3 +1831,85 @@ message CMsgDOTAPCBangTimedReward { optional string pcbangname = 3; } +message CMsgDOTACompendiumInGamePredictionResults { + message PredictionResult { + optional uint32 prediction_id = 1; + optional uint32 prediction_value = 2; + } + + repeated .CMsgDOTACompendiumInGamePredictionResults.PredictionResult results = 1; + optional uint32 league_id = 2; + optional bool predictions_closed = 3; +} + +message CMsgClientToGCSelectCompendiumInGamePrediction { + message Prediction { + optional uint32 prediction_id = 1; + optional uint32 prediction_value = 2; + } + + optional uint64 match_id = 1; + repeated .CMsgClientToGCSelectCompendiumInGamePrediction.Prediction predictions = 2; +} + +message CMsgClientToGCSelectCompendiumInGamePredictionResponse { + enum EResult { + SUCCESS = 0; + INVALID_MATCH = 1; + PREDICTIONS_ARE_CLOSED = 2; + OTHER_ERROR = 3; + } + + optional .CMsgClientToGCSelectCompendiumInGamePredictionResponse.EResult result = 1 [default = SUCCESS]; +} + +message CMsgClientToGCOpenPlayerCardPack { + optional uint64 player_card_pack_item_id = 1; +} + +message CMsgClientToGCOpenPlayerCardPackResponse { + enum Result { + SUCCESS = 1; + ERROR_INTERNAL = 2; + ERROR_FAILED_TO_FIND_PACK = 3; + ERROR_ITEM_NOT_CARD_PACK = 4; + ERROR_FAILED_CARD_CREATE = 5; + } + + optional .CMsgClientToGCOpenPlayerCardPackResponse.Result result = 1 [default = SUCCESS]; + repeated uint64 player_card_item_ids = 2; +} + +message CMsgClientToGCRecyclePlayerCard { + optional uint64 player_card_item_id = 1; +} + +message CMsgClientToGCRecyclePlayerCardResponse { + enum Result { + SUCCESS = 1; + ERROR_INTERNAL = 2; + ERROR_FAILED_TO_FIND_PLAYER_CARD = 3; + ERROR_ITEM_NOT_PLAYER_CARD = 4; + ERROR_FAILED_DUST_CARD_CREATE = 5; + } + + optional .CMsgClientToGCRecyclePlayerCardResponse.Result result = 1 [default = SUCCESS]; + optional uint32 dust_amount = 2; +} + +message CMsgClientToGCCreatePlayerCardPack { + optional uint64 card_dust_item_id = 1; +} + +message CMsgClientToGCCreatePlayerCardPackResponse { + enum Result { + SUCCESS = 1; + ERROR_INTERNAL = 2; + ERROR_INSUFFICIENT_DUST = 3; + ERROR_ITEM_NOT_DUST_ITEM = 4; + ERROR_FAILED_CARD_PACK_CREATE = 5; + } + + optional .CMsgClientToGCCreatePlayerCardPackResponse.Result result = 1 [default = SUCCESS]; +} + diff --git a/proto/dota_gcmessages_client_fantasy.proto b/proto/dota_gcmessages_client_fantasy.proto index 4cf05bf5..bf276a41 100644 --- a/proto/dota_gcmessages_client_fantasy.proto +++ b/proto/dota_gcmessages_client_fantasy.proto @@ -834,3 +834,62 @@ message CMsgDOTAPassportVote { repeated .CMsgDOTAPassportPlayerCardChallenge player_card_challenges = 4; } +message CMsgDOTAFantasyPlayerMatchStats { + message Match { + optional uint64 match_id = 1; + optional uint32 series_id = 2; + optional uint32 series_type = 3; + optional uint32 level = 4; + optional uint32 kills = 5; + optional uint32 deaths = 6; + optional uint32 assists = 7; + optional uint32 last_hits = 8; + optional uint32 denies = 9; + optional float gpm = 10; + optional float xppm = 11; + optional float stuns = 12; + optional float healing = 13; + optional uint32 tower_kills = 14; + optional uint32 roshan_kills = 15; + } + + optional uint32 player_account_id = 1; + repeated .CMsgDOTAFantasyPlayerMatchStats.Match matches = 2; +} + +message CMsgClientToGCGetPlayerCardRosterRequest { + optional uint32 league_id = 1; + optional uint32 timestamp = 2; +} + +message CMsgClientToGCGetPlayerCardRosterResponse { + enum Result { + SUCCESS = 0; + ERROR_UNSPECIFIED = 1; + ERROR_INVALID_LEAGUE_ID = 2; + ERROR_INVALID_TIMESTAMP = 3; + } + + optional .CMsgClientToGCGetPlayerCardRosterResponse.Result result = 1 [default = SUCCESS]; + repeated uint64 player_card_item_id = 2; +} + +message CMsgClientToGCSetPlayerCardRosterRequest { + optional uint32 league_id = 1; + optional uint32 timestamp = 2; + optional uint32 slot = 3; + optional uint64 player_card_item_id = 4; +} + +message CMsgClientToGCSetPlayerCardRosterResponse { + enum Result { + SUCCESS = 0; + ERROR_UNSPECIFIED = 1; + ERROR_INVALID_LEAGUE_ID = 2; + ERROR_INVALID_TIMESTAMP = 3; + ERROR_PLAYER_CARD_NOT_OWNED = 4; + } + + optional .CMsgClientToGCSetPlayerCardRosterResponse.Result result = 1 [default = SUCCESS]; +} + diff --git a/proto/dota_gcmessages_client_match_management.proto b/proto/dota_gcmessages_client_match_management.proto index e6c0e9e4..6e72c64b 100644 --- a/proto/dota_gcmessages_client_match_management.proto +++ b/proto/dota_gcmessages_client_match_management.proto @@ -30,6 +30,7 @@ enum EStartFindingMatchResult { k_EStartFindingMatchResult_WeekendTourneyIndividualBuyInTooLarge = 116; k_EStartFindingMatchResult_WeekendTourneyTeamBuyInTooLarge = 117; k_EStartFindingMatchResult_MemberMissingEventOwnership = 118; + k_EStartFindingMatchResult_WeekendTourneyNotUnlocked = 119; } message CMsgStartFindingMatch { @@ -366,3 +367,46 @@ message CMsgDOTAGroupMergeReply { optional .EDOTAGroupMergeResult result = 1 [default = k_EDOTAGroupMergeResult_OK]; } +message CMsgSpectatorLobbyGameDetails { + optional uint32 language = 1; + optional uint64 match_id = 2; + optional fixed64 server_steam_id = 3; + optional string stream_url = 4; + optional string stream_name = 5; + optional uint32 league_id = 6; + optional uint32 series_id = 7; + optional uint32 series_type = 8; + optional uint32 series_game = 9; + optional uint32 team1_id = 10; + optional uint32 team2_id = 11; + optional string stage_name = 12; +} + +message CMsgSetSpectatorLobbyDetails { + optional uint64 lobby_id = 1; + optional string lobby_name = 2; + optional string pass_key = 3; + optional .CMsgSpectatorLobbyGameDetails game_details = 4; +} + +message CMsgCreateSpectatorLobby { + optional uint32 client_version = 1; + optional .CMsgSetSpectatorLobbyDetails details = 2; +} + +message CMsgSpectatorLobbyList { +} + +message CMsgSpectatorLobbyListResponse { + message SpectatorLobby { + optional uint64 lobby_id = 1; + optional string game_name = 2; + optional bool requires_pass_key = 3; + optional uint32 leader_account_id = 4; + optional uint32 member_count = 5; + optional .CMsgSpectatorLobbyGameDetails game_details = 7; + } + + repeated .CMsgSpectatorLobbyListResponse.SpectatorLobby lobbies = 1; +} + diff --git a/proto/dota_gcmessages_client_team.proto b/proto/dota_gcmessages_client_team.proto index 9351efa3..817d1dfd 100644 --- a/proto/dota_gcmessages_client_team.proto +++ b/proto/dota_gcmessages_client_team.proto @@ -199,7 +199,7 @@ message CMsgDOTATeamInvite_InviterToGC { message CMsgDOTATeamInvite_GCImmediateResponseToInviter { optional .ETeamInviteResult result = 1 [default = TEAM_INVITE_SUCCESS]; optional string invitee_name = 2; - optional uint32 required_level = 3; + optional uint32 required_badge_level = 3; } message CMsgDOTATeamInvite_GCRequestToInvitee { diff --git a/proto/dota_gcmessages_client_watch.proto b/proto/dota_gcmessages_client_watch.proto index 7019b5b2..d9a2ac3c 100644 --- a/proto/dota_gcmessages_client_watch.proto +++ b/proto/dota_gcmessages_client_watch.proto @@ -133,9 +133,9 @@ message CMsgDOTAMatchMinimal { optional fixed32 start_time = 2; optional uint32 duration = 3; optional .DOTA_GameMode game_mode = 4 [default = DOTA_GAMEMODE_NONE]; - optional uint32 winning_team = 5; repeated .CMsgDOTAMatchMinimal.Player players = 6; optional .CMsgDOTAMatchMinimal.League league = 7; + optional .EMatchOutcome match_outcome = 8 [default = k_EMatchOutcome_Unknown]; } message CDOTAReplayDownloadInfo { diff --git a/proto/dota_gcmessages_common.proto b/proto/dota_gcmessages_common.proto index 417dd37b..559a39ab 100644 --- a/proto/dota_gcmessages_common.proto +++ b/proto/dota_gcmessages_common.proto @@ -43,6 +43,7 @@ enum DOTA_TournamentEvents { } enum DOTA_COMBATLOG_TYPES { + DOTA_COMBATLOG_INVALID = -1; DOTA_COMBATLOG_DAMAGE = 0; DOTA_COMBATLOG_HEAL = 1; DOTA_COMBATLOG_MODIFIER_ADD = 2; @@ -268,7 +269,7 @@ message CAdditionalEquipSlot { } message CMsgDOTACombatLogEntry { - optional .DOTA_COMBATLOG_TYPES type = 1 [default = DOTA_COMBATLOG_DAMAGE]; + optional .DOTA_COMBATLOG_TYPES type = 1 [default = DOTA_COMBATLOG_INVALID]; optional uint32 target_name = 2; optional uint32 target_source_name = 3; optional uint32 attacker_name = 4; @@ -720,14 +721,21 @@ message CMsgDOTASeasonPredictions { message Choice { optional uint32 value = 1; optional string name = 2; + optional uint32 min_raw_value = 3; + optional uint32 max_raw_value = 4; } message Answers { repeated uint32 answer_id = 1; } + message QueryKeyValues { + optional string name = 1; + optional string value = 2; + } + message Prediction { - optional uint32 type = 1; + optional .CMsgDOTASeasonPredictions.ePredictionType type = 1 [default = Generic]; optional string question = 2; repeated .CMsgDOTASeasonPredictions.Choice choices = 3; optional uint32 team_id = 4; @@ -740,6 +748,27 @@ message CMsgDOTASeasonPredictions { optional uint32 answer_type = 11; optional uint32 answer_id = 12; repeated .CMsgDOTASeasonPredictions.Answers answers = 13; + optional string query_name = 14; + optional uint32 lock_on_selection_id = 15; + optional uint32 lock_on_selection_value = 16; + optional bool lock_on_selection_set = 17; + } + + message InGamePrediction { + optional uint32 id = 1; + optional string name = 2; + optional .CMsgDOTASeasonPredictions.ePredictionType type = 3 [default = Generic]; + optional .CMsgDOTASeasonPredictions.eRandomSelectionGroup_t group = 4 [default = EarlyGame]; + optional string question = 5; + repeated .CMsgDOTASeasonPredictions.Choice choices = 6; + repeated string required_heroes = 7; + optional string query_name = 8; + repeated .CMsgDOTASeasonPredictions.QueryKeyValues query_values = 9; + optional .CMsgDOTASeasonPredictions.eResolutionType_t answer_resolution_type = 10 [default = InvalidQuery]; + optional uint32 points_to_grant = 11; + optional uint32 reward_action = 12; + optional uint32 debug_force_selection = 13; + optional .CMsgDOTASeasonPredictions.eRawValueType_t raw_value_type = 14 [default = Number]; } enum ePredictionType { @@ -748,6 +777,7 @@ message CMsgDOTASeasonPredictions { Team = 2; Player = 3; Special = 4; + YesNo = 5; } enum eAnswerType { @@ -758,9 +788,37 @@ message CMsgDOTASeasonPredictions { AnswerTeam = 4; SingleTime = 5; MultipleTime = 6; + NoAnswer = 7; + } + + enum eResolutionType_t { + InvalidQuery = 0; + FirstToPassQuery = 1; + LastToPassQuery = 2; + LastRemainingQuery = 3; + MaxToPassQuery = 4; + MinToPassQuery = 5; + SumQuery = 6; + MaxTeamSumToPassQuery = 7; + MinTeamSumToPassQuery = 8; + } + + enum eRandomSelectionGroup_t { + EarlyGame = 0; + MidGame = 1; + LateGame = 2; + Count = 3; + } + + enum eRawValueType_t { + Number = 0; + Time = 1; } repeated .CMsgDOTASeasonPredictions.Prediction predictions = 1; + repeated .CMsgDOTASeasonPredictions.InGamePrediction in_game_predictions = 2; + optional uint32 in_game_prediction_count_per_game = 3; + optional uint32 in_game_prediction_voting_period_minutes = 4; } message CMsgDOTAMatch { @@ -890,5 +948,18 @@ message CMsgDOTAMatch { optional uint32 radiant_team_score = 48; optional uint32 dire_team_score = 49; optional .EMatchOutcome match_outcome = 50 [default = k_EMatchOutcome_Unknown]; + optional uint32 tournament_id = 51; + optional uint32 tournament_round = 52; + optional uint32 pre_game_duration = 53; +} + +message CMsgPlayerCard { + message StatModifier { + optional uint32 stat = 1; + optional uint32 value = 2; + } + + optional uint32 account_id = 1; + repeated .CMsgPlayerCard.StatModifier stat_modifier = 2; } diff --git a/proto/dota_gcmessages_common_match_management.proto b/proto/dota_gcmessages_common_match_management.proto index 3f29ecf2..57e61ab0 100644 --- a/proto/dota_gcmessages_common_match_management.proto +++ b/proto/dota_gcmessages_common_match_management.proto @@ -60,8 +60,6 @@ message CSODOTAParty { optional uint32 open_guild_id = 30; repeated uint32 common_guilds = 31; optional uint32 low_priority_games_remaining = 35; - optional uint32 min_level = 36; - optional uint32 max_level = 37; repeated .EEvent active_ingame_events = 39; optional bool open_for_join_requests = 40; repeated .CSODOTAPartyInvite sent_invites = 41; @@ -215,6 +213,7 @@ message CSODOTALobby { CASUAL_1V1_MATCH = 8; WEEKEND_TOURNEY = 9; LOCAL_BOT_MATCH = 10; + SPECTATOR = 11; } optional uint64 lobby_id = 1 [(key_field) = true]; diff --git a/proto/dota_gcmessages_msgid.proto b/proto/dota_gcmessages_msgid.proto index 6a63fc25..4a15743b 100644 --- a/proto/dota_gcmessages_msgid.proto +++ b/proto/dota_gcmessages_msgid.proto @@ -122,10 +122,7 @@ enum EDOTAGCMsg { k_EMsgGCGenerateDiretidePrizeListResponse = 7180; k_EMsgGCStorePromoPagesRequest = 7182; k_EMsgGCStorePromoPagesResponse = 7183; - k_EMsgGCSpawnLootGreevil = 7184; - k_EMsgGCDismissLootGreevil = 7185; k_EMsgGCToGCMatchCompleted = 7186; - k_EMsgGCDismissLootGreevilResponse = 7187; k_EMsgGCBalancedShuffleLobby = 7188; k_EMsgGCToGCCheckLeaguePermission = 7189; k_EMsgGCToGCCheckLeaguePermissionResponse = 7190; @@ -311,7 +308,6 @@ enum EDOTAGCMsg { k_EMsgDOTAFriendRecruitInviteAcceptDecline = 7396; k_EMsgGCPartyLeaderWatchGamePrompt = 7397; k_EMsgDOTAFrostivusTimeElapsed = 7398; - k_EMsgGCToGCGrantEarnedLicense = 7399; k_EMsgDOTALiveLeagueGameUpdate = 7402; k_EMsgDOTAChatGetUserList = 7403; k_EMsgDOTAChatGetUserListResponse = 7404; @@ -352,8 +348,6 @@ enum EDOTAGCMsg { k_EMsgGCEventGameCreate = 7443; k_EMsgGCPerfectWorldUserLookupRequest = 7444; k_EMsgGCPerfectWorldUserLookupResponse = 7445; - k_EMsgGCToGCIncrementRecruitmentSDO = 7446; - k_EMsgGCToGCIncrementRecruitmentLevel = 7447; k_EMsgGCFantasyRemoveOwner = 7448; k_EMsgGCFantasyRemoveOwnerResponse = 7449; k_EMsgGCRequestBatchPlayerResources = 7450; @@ -403,7 +397,6 @@ enum EDOTAGCMsg { k_EMsgGCToClientTournamentItemDrop = 7495; k_EMsgSQLDelayedGrantLeagueDrop = 7496; k_EMsgServerGCUpdateSpectatorCount = 7497; - k_EMsgDOTAStartDailyHeroChallengeRequest = 7498; k_EMsgGCFantasyPlayerScoreDetailsRequest = 7499; k_EMsgGCFantasyPlayerScoreDetailsResponse = 7500; k_EMsgGCToGCEmoticonUnlock = 7501; @@ -449,7 +442,6 @@ enum EDOTAGCMsg { k_EMsgClientToGCCreateHeroStatue = 7547; k_EMsgGCToClientHeroStatueCreateResult = 7548; k_EMsgGCGCToLANServerRelayConnect = 7549; - k_EMsgSignOutAssassinMiniGameInfo = 7550; k_EMsgServerToGCGetIngameEventData = 7551; k_EMsgGCToGCUpdateIngameEventDataBroadcast = 7552; k_EMsgGCToServerIngameEventData_OraclePA = 7553; @@ -511,7 +503,6 @@ enum EDOTAGCMsg { k_EMsgClientToGCCreateTeamShowcase = 8002; k_EMsgGCToClientTeamShowcaseCreateResult = 8003; k_EMsgServerToGCLockCharmTrading = 8004; - k_EMsgDOTACNY2015EventPointUsage = 8005; k_EMsgClientToGCPlayerStatsRequest = 8006; k_EMsgGCToClientPlayerStatsResponse = 8007; k_EMsgGCClearPracticeLobbyTeam = 8008; @@ -558,7 +549,6 @@ enum EDOTAGCMsg { k_EMsgCustomGameClientFinishedLoading = 8053; k_EMsgGCPracticeLobbyCloseBroadcastChannel = 8054; k_EMsgGCStartFindingMatchResponse = 8055; - k_EMsgSQLGCToGCUpdateHeroMMR = 8056; k_EMsgSQLGCToGCGrantAccountFlag = 8057; k_EMsgGCToGCGetAccountFlags = 8058; k_EMsgGCToGCGetAccountFlagsResponse = 8059; @@ -652,5 +642,30 @@ enum EDOTAGCMsg { k_EMsgGCToClientWageringUpdate = 8154; k_EMsgGCToClientArcanaVotesUpdate = 8155; k_EMsgClientToGCAddTI6TreeProgress = 8156; + k_EMsgClientToGCSetSpectatorLobbyDetails = 8157; + k_EMsgClientToGCSetSpectatorLobbyDetailsResponse = 8158; + k_EMsgClientToGCCreateSpectatorLobby = 8159; + k_EMsgClientToGCCreateSpectatorLobbyResponse = 8160; + k_EMsgClientToGCSpectatorLobbyList = 8161; + k_EMsgClientToGCSpectatorLobbyListResponse = 8162; + k_EMsgSpectatorLobbyGameDetails = 8163; + k_EMsgServerToGCStartCompendiumInGamePredictions = 8164; + k_EMsgServerToGCEndCompendiumInGamePredictions = 8165; + k_EMsgServerToGCCompendiumInGamePredictionResults = 8166; + k_EMsgServerToGCCloseCompendiumInGamePredictionVoting = 8167; + k_EMsgClientToGCOpenPlayerCardPack = 8168; + k_EMsgClientToGCOpenPlayerCardPackResponse = 8169; + k_EMsgClientToGCSelectCompendiumInGamePrediction = 8170; + k_EMsgClientToGCSelectCompendiumInGamePredictionResponse = 8171; + k_EMsgClientToGCWeekendTourneyGetPlayerStats = 8172; + k_EMsgClientToGCWeekendTourneyGetPlayerStatsResponse = 8173; + k_EMsgClientToGCRecyclePlayerCard = 8174; + k_EMsgClientToGCRecyclePlayerCardResponse = 8175; + k_EMsgClientToGCCreatePlayerCardPack = 8176; + k_EMsgClientToGCCreatePlayerCardPackResponse = 8177; + k_EMsgClientToGCGetPlayerCardRosterRequest = 8178; + k_EMsgClientToGCGetPlayerCardRosterResponse = 8179; + k_EMsgClientToGCSetPlayerCardRosterRequest = 8180; + k_EMsgClientToGCSetPlayerCardRosterResponse = 8181; } diff --git a/proto/dota_shared_enums.proto b/proto/dota_shared_enums.proto index 5504c735..cb147eba 100644 --- a/proto/dota_shared_enums.proto +++ b/proto/dota_shared_enums.proto @@ -114,6 +114,7 @@ enum Fantasy_Selection_Mode { FANTASY_SELECTION_PRE_DRAFT = 6; FANTASY_SELECTION_DRAFTING = 7; FANTASY_SELECTION_REGULAR_SEASON = 8; + FANTASY_SELECTION_CARD_BASED = 9; } enum DOTAChatChannelType_t { @@ -136,6 +137,7 @@ enum DOTAChatChannelType_t { DOTAChannelType_CustomGame = 16; DOTAChannelType_Private = 17; DOTAChannelType_PostGame = 18; + DOTAChannelType_BattleCup = 19; } enum EProfileCardSlotType { @@ -188,6 +190,7 @@ enum DOTAJoinLobbyResult { DOTA_JOIN_RESULT_NO_LOBBY_FOUND = 8; DOTA_JOIN_RESULT_LOBBY_FULL = 9; DOTA_JOIN_RESULT_CUSTOM_GAME_INCORRECT_VERSION = 10; + DOTA_JOIN_RESULT_TIMEOUT = 11; } enum SelectionPriorityType { diff --git a/proto/econ_gcmessages.proto b/proto/econ_gcmessages.proto index 662a8217..273aac3f 100644 --- a/proto/econ_gcmessages.proto +++ b/proto/econ_gcmessages.proto @@ -151,7 +151,6 @@ enum EGCItemMsg { k_EMsgGCToGCCheckAccountTradeStatusResponse = 2553; k_EMsgGCToGCGrantAccountRolledItems = 2554; k_EMsgGCToGCGrantSelfMadeItemToAccount = 2555; - k_EMsgSQLUpgradeBattleBooster = 2556; k_EMsgGCPartnerBalanceRequest = 2557; k_EMsgGCPartnerBalanceResponse = 2558; k_EMsgGCPartnerRechargeRedirectURLRequest = 2559; diff --git a/proto/gcsdk_gcmessages.proto b/proto/gcsdk_gcmessages.proto index f6ce7c97..cf5c6e88 100644 --- a/proto/gcsdk_gcmessages.proto +++ b/proto/gcsdk_gcmessages.proto @@ -169,6 +169,8 @@ message CMsgGCRequestSubGCSessionInfo { message CMsgGCRequestSubGCSessionInfoResponse { optional fixed32 ip = 1; optional bool trusted = 2; + optional uint32 port = 3; + optional bool success = 4; } message CMsgSOCacheHaveVersion { @@ -222,14 +224,16 @@ message CMsgGCToGCSOCacheSubscribe { } optional fixed64 subscriber = 1; - optional fixed64 subscribe_to = 2; + optional fixed64 subscribe_to_id = 2; optional fixed64 sync_version = 3; repeated .CMsgGCToGCSOCacheSubscribe.CMsgHaveVersions have_versions = 4; + optional uint32 subscribe_to_type = 5; } message CMsgGCToGCSOCacheUnsubscribe { optional fixed64 subscriber = 1; - optional fixed64 unsubscribe_from = 2; + optional fixed64 unsubscribe_from_id = 2; + optional uint32 unsubscribe_from_type = 3; } message CMsgGCClientPing { diff --git a/test/test.js b/test/test.js index c7a26e65..400dd629 100644 --- a/test/test.js +++ b/test/test.js @@ -109,85 +109,102 @@ var steam = require("steam"), before(beConnectedToSteam); before(beLoggedInToSteam); - describe('Core', function() { - describe('#launch', function() { + describe('Core', function () { + describe('#launch', function () { it('should connect to Dota2 GC (recv \'ready\' event', connectToDota2); }); - describe('#exit', function() { + describe('#exit', function () { // TODO: Not sure how we test this. Need to run it after all the other tests too. it('should disconnect from Dota2 GC'); }); }); - describe('Utilities', function() { - describe('#ToAccountID', function() { + describe('Utilities', function () { + describe('#ToAccountID', function () { it('should convert a 64-bit Steam ID into a 32-bit account ID', convertSteamIDToAccountID); }); - describe('#ToSteamID', function() { + describe('#ToSteamID', function () { it('should convert a 32-bit account ID into a 64-bit Steam ID ', convertAccountIDToSteamID); }); }); - describe('Inventory', function() { + describe('Inventory', function () { // TODO: No idea how we test these. - describe('#setItemPositions', function() { + describe('#setItemPositions', function () { it('should move the given items to the given positions'); }); - describe('#deleteItem', function() { + describe('#deleteItem', function () { it('should delete the given item'); }); }); - describe('Chat', function() { - describe('#joinChat', function() { + describe('Chat', function () { + describe('#joinChat', function () { it('should join a chat channel'); // TODO }); - describe('#leaveChat', function() { + describe('#leaveChat', function () { it('should leave a chat channel'); // TODO }); - describe('#sendMessage', function() { + describe('#sendMessage', function () { it('should a message to a chat channel'); // TODO }); - describe('#requestChatChannels', function() { - it('should fetch a list of chat channels from the GC'); // TODO + describe('#requestChatChannels', function () { + it('should fetch a list of chat channels from the GC', function (done) { + Dota2.on('chatChannelsData', function (channels) { + should.exist(channels); + should(channels.length).above(0); + should.exist(channels[0].channel_name); + channels[0].num_members.should.be.aboveOrEqual(0); + should.exist(channels[0].channel_type); + done(); + }); + Dota2.requestChatChannels(); + }); }); }); - describe('Guild', function() { - describe('#requestGuildData', function() { + describe('Guild', function () { + describe('#requestGuildData', function () { it('should return a list of guid IDs and a list of any open parties they have'); // TODO }); - describe('#inviteToGuild', function(){ + describe('#inviteToGuild', function () { it('should invite an account to join a guild'); // TODO }); - describe('#cancelInviteToGuild', function(){ + describe('#cancelInviteToGuild', function () { it('should cancel a pending guild invitation'); // TODO }); - describe('#setGuildAccountRole', function(){ + describe('#setGuildAccountRole', function () { it('should set a given account\'s role within a guild'); // TODO }); }); - describe('Community', function() { - describe('#requestPlayerMatchHistory', function(){ - it('should fetch a paginated and filtered list of a player\'s matches'); // TODO + describe('Community', function () { + describe('#requestPlayerMatchHistory', function () { + it('should fetch a paginated and filtered list of a player\'s matches', function (done) { + Dota2.requestPlayerMatchHistory(parseInt(GABE_ACCOUNT_ID), null, function (err, data) { + should.exist(data); + should.exist(data.matches); + data.matches.length.should.be.aboveOrEqual(0); + done(err); + }); + }); }); - // describe('#requestProfile', function(){ + // describe('#requestProfile', function () { // it('should fetch an account\'s profile'); // TODO // }); - describe('#requestProfileCard', function(done){ - it('should fetch an account\'s profile card', function(done){ + describe('#requestProfileCard', function (done){ + it('should fetch an account\'s profile card', function (done) { Dota2.requestProfileCard(parseInt(GABE_ACCOUNT_ID), function (err, data) { should.exist(data.account_id); done(err); @@ -195,21 +212,51 @@ var steam = require("steam"), }); }); - // describe('#requestPassportData', function(){ + // describe('#requestPassportData', function () { // it('should fetch an account\'s passport (compendium) data'); // TODO // }); - describe('#requestHallOfFame', function(){ + describe('#requestHallOfFame', function () { it('should fetch a given weeks hall of fame data'); // TODO }); }); - describe('Matches', function() { - describe('#requestMatches', function(){ - it('should fetch a list of matches matching the given search criteria'); // TODO + describe('Matches', function () { + describe('#requestMatches', function () { + it('should fetch a list of matches matching the given search criteria', function (done) { + Dota2.requestMatches([], function(err, matchesData) { + should.exist(matchesData); + matchesData.total_results.should.be.aboveOrEqual(0); + matchesData.results_remaining.should.be.aboveOrEqual(0); + should.exist(matchesData.matches); + done(err); + }); + }); }); - describe('#requestMatchDetails', function(){ + describe('#requestMatchMinimalDetails', function () { + it ('should fetch a list of minimal match data corresponding to the given ids', done => { + Dota2.requestMatchMinimalDetails([2466191302], function (err, data) { + should.exist(data); + should.exist(data.matches); + should.exist(data.matches[0].match_id); + data.matches[0].match_id.toString().should.be.eql('2466191302'); + should.exist(data.matches[0].match_outcome); + should.exist(data.matches[0].players) + data.matches[0].players.length.should.be.above(0); + should.exist(data.matches[0].players[0].account_id); + should.exist(data.matches[0].players[0].hero_id); + should.exist(data.matches[0].players[0].kills); + should.exist(data.matches[0].players[0].deaths); + should.exist(data.matches[0].players[0].assists); + should.exist(data.matches[0].players[0].items); + should.exist(data.matches[0].players[0].player_slot); + done(err); + }); + }); + }); + + describe('#requestMatchDetails', function () { it('should fetch data on a given match id', function(done){ Dota2.requestMatchDetails(2038049617, function(err, details){ should.exist(details.match.replay_salt); @@ -218,96 +265,165 @@ var steam = require("steam"), }); }); - describe('#requestMatchmakingStats', function(){ - it('should fetch some data on the current state of matchmaking'); // TODO + describe('#requestMatchmakingStats', function () { + it('should fetch some data on the current state of matchmaking', function(done){ + Dota2.on('matchmakingStatsData', function (version, match_groups, data) { + should.exist(data.match_groups); + should(match_groups.length).above(0); + should.exist(match_groups[0].players_searching); + should.exist(match_groups[0].status); + done(); + }); + Dota2.requestMatchmakingStats(); + }); }); }); - describe('Parties', function() { - describe('#respondPartyInvite', function(){ + describe('Parties', function () { + describe('#respondPartyInvite', function () { it('should respond to an incoming party invite'); // TODO }); - describe('#inviteToParty', function(){ + describe('#inviteToParty', function () { it('should invite a given account ID to a party'); // TODO }); - describe('#kickFromParty', function(){ + describe('#kickFromParty', function () { it('should kick a given user from a party'); // TODO }); - describe('#setPartyCoach', function(){ + describe('#setPartyCoach', function () { it('should set the node-dota2 instance to be this party\'s coach'); // TODO }); - describe('#leaveParty', function(){ + describe('#leaveParty', function () { it('should leave the party'); // TODO }); }); - describe('Lobbies', function() { - describe('#joinPracticeLobby', function(){ + describe('Lobbies', function () { + describe('#joinPracticeLobby', function () { it('should join a lobby with the given id'); // TODO }); - describe('#createPracticeLobby', function(){ + describe('#createPracticeLobby', function () { it('should create a lobby'); // TODO }); - describe('#createTournamentLobby', function(){ + describe('#createTournamentLobby', function () { it('should create a tournament lobby'); // TODO }); - describe('#balancedShuffleLobby', function(){ + describe('#balancedShuffleLobby', function () { it('should shuffle the teams within the lobby'); // TODO }); - describe('#flipLobbyTeams', function(){ + describe('#flipLobbyTeams', function () { it('should flip the teams within the lobby'); // TODO }); - describe('#configPracticeLobby', function(){ + describe('#configPracticeLobby', function () { it('should (re)configure the lobby'); // TODO }); - describe('#launchPracticeLobby', function(){ + describe('#launchPracticeLobby', function () { it('should launch the lobby and begin a match'); // TODO }); - describe('#inviteToLobby', function(){ + describe('#inviteToLobby', function () { it('should invite the given account to a lobby'); // TODO }); - describe('#practiceLobbyKick', function(){ + describe('#practiceLobbyKick', function () { it('should kick a given account from a lobby'); // TODO }); - describe('#leavePracticeLobby', function(){ + describe('#leavePracticeLobby', function () { it('should leave a lobby'); // TODO }); - describe('#requestPracticeLobbyList', function(){ + describe('#requestPracticeLobbyList', function () { it('should do something'); // TODO }); - describe('#requestFriendPractiseLobbyList', function(){ + describe('#requestFriendPractiseLobbyList', function () { it('should do something'); // TODO }); }); - describe('Leagues', function() { - describe('#requestLeaguesInMonth', function(){ - it('should fetch data on leages being played in the given month'); // TODO + describe('Leagues', function () { + describe('#requestLeaguesInMonth', function () { + it('should fetch data on leages being played in the given month', function (done) { + Dota2.on('leaguesInMonthData', function (month, year, leagues){ + should.exist(month); + should.exist(year); + should(leagues.length).above(0); + should.exist(leagues[0].league_id); + should(leagues[0].schedule.length).above(0); + done(); + }); + Dota2.requestLeaguesInMonth(8,2015); + }); }); - describe('#requestLeagueInfo', function(){ - it('should fetch data on all official leagues'); // TODO + describe('#requestLeagueInfo', function () { + it('should fetch data on all official leagues', function (done) { + Dota2.on('leagueData', function (leagues){ + should(leagues.length).above(0); + should.exist(leagues[0].league_id); + done(); + }); + Dota2.requestLeagueInfo(); + }); + }); + + describe('#requestTopLeagueMatches', function () { + it('should fetch data on all top league matches', function (done) { + Dota2.on('topLeagueMatchesData', function (matches){ + should(matches.length).above(0); + should.exist(matches[0].match_id); + should.exist(matches[0].players); + should(matches[0].players.length).above(0); + should.exist(matches[0].league.league_id); + done(); + }); + Dota2.requestTopLeagueMatches(); + }); }); }); - describe('SourceTV', function() { - describe('#requestSourceTVGames', function(){ - it('should fetch a list of ongoing matches matching the search criteria'); // TODO + describe('SourceTV', function () { + describe('#requestSourceTVGames', function () { + it('should fetch a list of ongoing matches matching the search criteria', done => { + Dota2.on('sourceTVGamesData', function (games) { + should.exist(games); + should(games.num_games).above(0); + done(); + }); + Dota2.requestSourceTVGames(); + }); }); }); + + describe('Teams', function () { + describe('#requestMyTeams', function () { + it('should fetch a list of teams of which I\'m a member', done => { + Dota2.requestMyTeams(function (err, teamData) { + should.exist(teamData.teams); + done(err); + }); + }); + }); + + // describe('#requestProTeamList', function () { + // it('should fetch a list of pro teams', function(done){ + // Dota2.requestProTeamList(function (err, teamData) { + // should.exist(teamData.teams); + // done(err); + // }); + // }); + // }); + }); + + });