Skip to content
This repository has been archived by the owner on Jun 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #361 from Arcana/dev
Browse files Browse the repository at this point in the history
Bump to 4.1.0
  • Loading branch information
Crazy-Duck authored Oct 18, 2016
2 parents bea2b55 + ffb0ad8 commit a84f437
Show file tree
Hide file tree
Showing 24 changed files with 593 additions and 160 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
language: node_js
node_js:
- "6.2.1"
- "4.4.5"
- "6.7.0"
- "4.6.0"
124 changes: 100 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ node-dota2
========

[![NPM version](https://img.shields.io/npm/v/dota2.svg)](https://npmjs.org/package/dota2 "View this project on NPM")
[![Build Status](https://img.shields.io/travis/RJacksonm1/node-dota2.svg)](https://travis-ci.org/RJacksonm1/node-dota2 "View this project's build information")
[![Dependency Status](https://img.shields.io/david/RJacksonm1/node-dota2.svg)](https://david-dm.org/RJacksonm1/node-dota2 "Check this project's dependencies")
[![Build Status](https://img.shields.io/travis/Arcana/node-dota2.svg)](https://travis-ci.org/Arcana/node-dota2 "View this project's build information")
[![Dependency Status](https://img.shields.io/david/Arcana/node-dota2.svg)](https://david-dm.org/Arcana/node-dota2 "Check this project's dependencies")

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.
Check out RJackson1's blog post (his 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

### `3.*.*` to `4.0.0`
### `3.*.*` to `4.*.0`

A few backwards incompatible API changes were included with version 4.0.0.

Expand Down Expand Up @@ -46,6 +46,13 @@ var Steam = require('steam'),
Dota2 = new dota2.Dota2Client(steamClient, true, false);
```

## Disclaimer
We do not in any way encourage people to use their own accounts when using this library.
This library tries to mimic the behavior of the Dota 2 client to allow people to programmatically interact with the Dota 2 GC,
however we make no efforts to hide this fact and it's pretty easy for Valve to detect clients using this library based on the generated traffic.
While Valve has not yet expressed a dislike regarding reverse engineering projects like this one,
it's not unimaginable that this might one day change and result in VAC bans.

## 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.
Expand Down Expand Up @@ -106,9 +113,9 @@ Attempts to delete an item. Requires the GC to be ready (listen for the `ready`
### Chat
**_Limited Steam accounts cannot interact with chat!_**

#### joinChat(channel, [type])
* `channel` - A string for the channel name.
* `[type]` - The type of the channel being joined. Defaults to `Dota2.schema.DOTAChatChannelType_t.DOTAChannelType_Custom`.
#### joinChat(channel_name, [channel_type])
* `channel_name` - A string for the channel name.
* `[channel_type]` - The type of the channel being joined. Defaults to `Dota2.schema.DOTAChatChannelType_t.DOTAChannelType_Custom`.

Joins a chat channel. If the chat channel with the given name doesn't exist, it
is created. Listen for the `chatMessage` event for other people's chat messages.
Expand All @@ -117,28 +124,35 @@ Notable channels:
* `Guild_##########` - The chat channel of the guild with guild_id = ##########
* `Lobby_##########` - The chat channel of the lobby with lobby_id = ##########

#### leaveChat(channel)
* `channel` - A string for the channel name.
#### leaveChat(channel_name, [channel_type])
* `channel_name` - A string for the channel name.
* `[channel_type]` - The type of the channel you want to leave. Use the `Dota2.schema.DOTAChatChannelType_t` enum.

Leaves a chat channel.
Leaves a chat channel. If you've joined different channels with the same name, specify the type to prevent unexpected behaviour.

#### sendMessage(channel, message)
#### sendMessage(channel, message, [channel_type])
* `channel` - A string for the channel name.
* `message` - The message you want to send.
* `[channel_type]` - The type of the channel you want to send a message to. Use the `Dota2.schema.DOTAChatChannelType_t` enum.

Sends a message to the specified chat channel. Won't send if you're not in the channel you try to send to.
If you've joined different channels with the same name, specify the type to prevent unexpected behaviour.

#### flipCoin(channel)
#### flipCoin(channel, [channel_type])
* `channel` - A string for the channel name.
* `[channel_type]` - The type of the channel you want to flip a coin in. Use the `Dota2.schema.DOTAChatChannelType_t` enum.

Sends a coin flip to the specified chat channel. Won't send if you're not in the channel you try to send to.
If you've joined different channels with the same name, specify the type to prevent unexpected behaviour.

#### rollDice(channel, min, max)
#### rollDice(channel, min, max, [channel_type])
* `channel` - A string for the channel name.
* `min` - Lower bound of the dice roll.
* `max` - Upper bound of the dice roll.
* `[channel_type]` - The type of the channel you want to roll a dice in. Use the `Dota2.schema.DOTAChatChannelType_t` enum.

Sends a dice roll to the specified chat channel. Won't send if you're not in the channel you try to send to.
If you've joined different channels with the same name, specify the type to prevent unexpected behaviour.

#### requestChatChannels()

Expand Down Expand Up @@ -222,6 +236,8 @@ Requests the list of pro teams.
* `[matches_requested]` - How many matches to retrieve
* `[hero_id]` - The ID of the hero the given account ID had played
* `[request_id]` - I have no idea.
* `[include_practice_matches]` - Do you want practice matches in the result sets?
* `[include_custom_games]` - Do you want custom games in the result sets?
* `[callback]` - optional callback, returns args: `err, response`.

Requests the given player's match history. The responses are paginated, but you can use the `start_at_match_id` and `matches_requested` options to loop through them.
Expand Down Expand Up @@ -267,6 +283,13 @@ Sends a message to the Game Coordinator requesting one or multiple `account_ids`

Sends a message to the Game Coordinator requesting `account_id`'s trophy data. Provide a callback or listen for `trophyListData` event for Game Coordinator's response. Requires the GC to be ready (listen for the `ready` event before calling). Notably, this data contains the `profile_name` field, which is the user's name displayed on their profile page in dota.

#### requestPlayerStats(account_id, [callback])
* `account_id` - Account ID (lower 32-bits of a 64-bit Steam ID) of the user whose player stats you wish to view.
* `[callback]` - optional callback, returns args: `err, response`.
*
Sends a message to the Game Coordinator requesting `account_id`'s player stats. Provide a callback or listen for `playerStatsData` event for Game Coordinator's response. Requires the GC to be ready (listen for the `ready` event before calling). This data contains all stats shown on a player's profile page.


### Matches
#### requestMatches(criteria, [callback])
* `[criteria]` - The options available for searching matches:
Expand Down Expand Up @@ -311,9 +334,10 @@ Sends a message to the Game Coordinator requesting the top matches of your frien

### Parties

### respondPartyInvite(id, accept)
* `[id]` - Number, party ID.
* `[accept]` - Accept or decline the invite.
### respondPartyInvite(id, accept, [ping_data])
* `id` - Number, party ID.
* `accept` - Accept or decline the invite.
* `[ping_data]` - Optional argument to be provided when accepting a party invite. For contents see `CMsgClientPingData`.

Responds to an incoming party invite. The `PartyInvite` property is cleared after the response has been sent.

Expand All @@ -336,6 +360,12 @@ Kicks a player from the party. This will create a new party if you aren't in one
Set the bot's status as a coach.


### setPartyLeader(id)
* `[id]` - The steam ID of new party leader.

Set the new party leader.


### leaveParty()

Leaves the current party. See the `Party` property.
Expand Down Expand Up @@ -511,6 +541,11 @@ Emitted when the GC is ready to receive messages. Be careful not to declare ano
### `unready`
Emitted when the connection status to the GC changes, and renders the library unavailable to interact. You should clear any event handlers set in the `ready` event here, otherwise you'll have multiple handlers for each message every time a new `ready` event is sent.

### `popup` (`type`, `popup`)
* `type` - The type of the popup. See `CMsgDOTAPopup.PopupID`
* `popup` - The raw popup data

Generic popup, can be produced for a plethora of reasons.

### `chatMessage` (`channel`, `senderName`, `message`, `chatObject`)
* `channel` - Channel name.
Expand Down Expand Up @@ -680,6 +715,31 @@ Emitted when GC responds to the `requestPassportData` method.

See the [protobuf schema](https://github.com/SteamRE/SteamKit/blob/master/Resources/Protobufs/dota/dota_gcmessages_client_fantasy.proto#L961) for `passportData`'s object structure.

### `playerStatsData` (`account_id`, `playerStats`)
* `account_id` - Account ID whom the stats belong to.
* `playerStats` - Statistics about the player. This entails:
* `account_id`
* `player_stats`
* `match_count`
* `mean_gpm`
* `mean_xppm`
* `mean_lasthits`
* `rampages`
* `triple_kills`
* `first_blood_claimed`
* `first_blood_given`
* `couriers_killed`
* `aegises_snatched`
* `cheeses_eaten`
* `creeps_stacked`
* `fight_score`
* `farm_score`
* `support_score`
* `push_score`
* `versatility_score`

Emitted when the GC responds to the `requestPlayerStats` method.

### `hallOfFameData` (`week`, `featuredPlayers`, `featuredFarmer`, `hallOfFameResponse`)
* `week` - Week the data is associated with.
* `featuredPlayers` - Array of featured players for that week. `[{ account_id, heroId, averageScaledMetric, numGames }]`
Expand Down Expand Up @@ -714,7 +774,7 @@ See the [protobuf schema](https://github.com/SteamRE/SteamKit/blob/5acc8bb72bb7f
* `matchmakingStatsResponse` - Raw response object.

Emitted when te GC response to the `requestMatchmakingStats` method. The array order dictates which matchmaking groups the figure belongs to.
The groups are discoverable through `regions.txt` in Dota 2's game files. We maintain an indicative list *without guarantees* in this README.
The groups are discoverable through [regions.txt](https://github.com/SteamDatabase/GameTracking/blob/master/dota/game/dota/pak01_dir/scripts/regions.txt) in Dota 2's game files. We maintain an indicative list *without guarantees* in this README.
This list is manually updated only when changes are detected by community members, so it can be out of date.
Here are the groups at the time of this sentence being written (with unecessary data trimmed out):

Expand All @@ -738,7 +798,8 @@ Here are the groups at the time of this sentence being written (with unecessary
"India": {"matchgroup": "16"},
"PerfectWorldTelecomGuangdong": {"matchgroup": "17"},
"PerfectWorldTelecomZhejiang": {"matchgroup": "18"},
"Japan": {"matchgroup": "19"}
"Japan": {"matchgroup": "19"},
"PerfectWorldTelecomWuhan": {"matchgroup": "20"}
```

### `topFriendMatchesData` (`matches`)
Expand All @@ -755,7 +816,7 @@ Emitted when the GC responds to the `requestTopFriendMatches` method.


### `practiceLobbyUpdate` (`lobby`)
* `lobby` - The full lobby object (see CSODOTALobby).
* `lobby` - The full lobby object (see `CSODOTALobby`).


Emitted when the GC sends a lobby snapshot. The GC is incredibly
Expand Down Expand Up @@ -815,7 +876,7 @@ Emitted when the GC has created the invitation. The invitation is only sent when
the invitee is online.

### `partyUpdate` (`party`)
* `party` - The full party object (see CSODOTAParty).
* `party` - The full party object (see `CSODOTAParty`).


Emitted when the GC sends a party snapshot. The GC is incredibly
Expand Down Expand Up @@ -919,13 +980,21 @@ Emitted when the GC responds to the `requestSourceTVGames` method. Multiple eve
* `EUROPE: 3`
* `KOREA: 4`
* `SINGAPORE: 5`
* `DUBAI: 6`
* `AUSTRALIA: 7`
* `STOCKHOLM: 8`
* `AUSTRIA: 9`
* `BRAZIL: 10`
* `SOUTHAFRICA: 11`
* `PERFECTWORLDTELECOM: 12`
* `PERFECTWORLDUNICOM: 13`
* `PWTELECOMSHANGHAI: 12`
* `PWUNICOM: 13`
* `CHILE: 14`
* `PERU: 15`
* `INDIA: 16`
* `PWTELECOMGUANGZHOU: 17`
* `PWTELECOMZHEJIANG: 18`
* `JAPAN: 19`
* `PWTELECOMWUHAN: 20`

Use this to pass valid server region data to `createPracticeLobby`.

Expand All @@ -946,8 +1015,15 @@ Use this to pass valid server region data to `createPracticeLobby`.
* `DOTA_GAMEMODE_POOL1: 13` - Limited Heroes
* `DOTA_GAMEMODE_FH: 14` - Compendium
* `DOTA_GAMEMODE_CUSTOM: 15` - Unknown, probably ti4 techies reveal.

Use this to pass valid game mode data to `createPracticeLobby`.
* `DOTA_GAMEMODE_CD: 16` - Captain's Draft
* `DOTA_GAMEMODE_BD: 17` - Balanced Draft
* `DOTA_GAMEMODE_ABILITY_DRAFT: 18` - Ability Draft
* `DOTA_GAMEMODE_EVENT: 19` - Unknown
* `DOTA_GAMEMODE_ARDM: 20` - All Random Death Match
* `DOTA_GAMEMODE_1V1MID: 21` - 1v1 Mid
* `DOTA_GAMEMODE_ALL_DRAFT: 22` - All Draft a.k.a. ranked all pick

Use this to pass valid game mode data to `createPracticeLobby`. This enum is built-in the protobuf schema and can be referenced by `Dota2.DOTA_GameMode`.



47 changes: 25 additions & 22 deletions handlers/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ var Dota2 = require("../index"),
util = require("util");

// Methods
Dota2.Dota2Client.prototype._getChannelByName = function(channel_name) {
Dota2.Dota2Client.prototype._getChannelByName = function(channel_name, channel_type) {
// Returns the channel corresponding to the given channel_name
if (this.chatChannels) {
return this.chatChannels.filter(
function(item) {
return (item.channel_name === channel_name);
if(channel_type >= 0)
return (item.channel_name === channel_name && item.channel_type === channel_type);
else
return (item.channel_name === channel_name);
}
)[0];
} else {
Expand All @@ -29,24 +32,24 @@ Dota2.Dota2Client.prototype._getChannelById = function(channel_id) {
}
}

Dota2.Dota2Client.prototype.joinChat = function(channel, type) {
type = type || Dota2.schema.DOTAChatChannelType_t.DOTAChannelType_Custom;
Dota2.Dota2Client.prototype.joinChat = function(channel_name, channel_type) {
channel_type = channel_type || Dota2.schema.DOTAChatChannelType_t.DOTAChannelType_Custom;

/* Attempts to join a chat channel. Expect k_EMsgGCJoinChatChannelResponse from GC */
if (this.debug) util.log("Joining chat channel: " + channel);
if (this.debug) util.log("Joining chat channel: " + channel_name);

var payload = new Dota2.schema.CMsgDOTAJoinChatChannel({
"channel_name": channel,
"channel_type": type
"channel_name": channel_name,
"channel_type": channel_type
});
this.sendToGC(Dota2.schema.EDOTAGCMsg.k_EMsgGCJoinChatChannel, payload);
};

Dota2.Dota2Client.prototype.leaveChat = function(channel) {
Dota2.Dota2Client.prototype.leaveChat = function(channel_name, channel_type) {
/* Attempts to leave a chat channel. GC does not send a response. */
if (this.debug) util.log("Leaving chat channel: " + channel);
if (this.debug) util.log("Leaving chat channel: " + channel_name);
// Clear cache
var cache = this._getChannelByName(channel);
var cache = this._getChannelByName(channel_name, channel_type);
if (cache === undefined) {
if (this.debug) util.log("Cannot leave a channel you have not joined.");
return;
Expand All @@ -58,11 +61,11 @@ Dota2.Dota2Client.prototype.leaveChat = function(channel) {
this.sendToGC(Dota2.schema.EDOTAGCMsg.k_EMsgGCLeaveChatChannel, payload);
};

Dota2.Dota2Client.prototype.sendMessage = function(channel, message) {
Dota2.Dota2Client.prototype.sendMessage = function(channel_name, message, channel_type) {
/* Attempts to send a message to a chat channel. GC does not send a response. */
if (this.debug) util.log("Sending message to " + channel);
if (this.debug) util.log("Sending message to " + channel_name);
// Check cache
var cache = this._getChannelByName(channel);
var cache = this._getChannelByName(channel_name, channel_type);
if (cache === undefined) {
if (this.debug) util.log("Cannot send message to a channel you have not joined.");
return;
Expand All @@ -75,11 +78,11 @@ Dota2.Dota2Client.prototype.sendMessage = function(channel, message) {
this.sendToGC(Dota2.schema.EDOTAGCMsg.k_EMsgGCChatMessage, payload);
};

Dota2.Dota2Client.prototype.shareLobby = function(channel) {
Dota2.Dota2Client.prototype.shareLobby = function(channel_name, channel_type) {
/* Attempts to send a message to a chat channel. GC does not send a response. */
if (this.debug) util.log("Sharing lobby to " + channel);
if (this.debug) util.log("Sharing lobby to " + channel_name);
// Check cache
var cache = this._getChannelByName(channel);
var cache = this._getChannelByName(channel_name, channel_type);
if (cache === undefined) {
if (this.debug) util.log("Cannot send message to a channel you have not joined.");
return;
Expand All @@ -97,11 +100,11 @@ Dota2.Dota2Client.prototype.shareLobby = function(channel) {
this.sendToGC(Dota2.schema.EDOTAGCMsg.k_EMsgGCChatMessage, payload);
};

Dota2.Dota2Client.prototype.flipCoin = function(channel) {
Dota2.Dota2Client.prototype.flipCoin = function(channel_name, channel_type) {
/* Attempts to send a coin flip to a chat channel. Expect a chatmessage in response. */
if (this.debug) util.log("Sending coin flip to " + channel);
if (this.debug) util.log("Sending coin flip to " + channel_name);
// Check cache
var cache = this._getChannelByName(channel);
var cache = this._getChannelByName(channel_name, channel_type);
if (cache === undefined) {
if (this.debug) util.log("Cannot send message to a channel you have not joined.");
return;
Expand All @@ -114,11 +117,11 @@ Dota2.Dota2Client.prototype.flipCoin = function(channel) {
this.sendToGC(Dota2.schema.EDOTAGCMsg.k_EMsgGCChatMessage, payload);
};

Dota2.Dota2Client.prototype.rollDice = function(channel, min, max) {
Dota2.Dota2Client.prototype.rollDice = function(channel_name, min, max, channel_type) {
/* Attempts to send a dice roll to a chat channel. Expect a chatmessage in response. */
if (this.debug) util.log("Sending dice roll to " + channel);
if (this.debug) util.log("Sending dice roll to " + channel_name);
// Check cache
var cache = this._getChannelByName(channel);
var cache = this._getChannelByName(channel_name, channel_type);
if (cache === undefined) {
if (this.debug) util.log("Cannot send message to a channel you have not joined.");
return;
Expand Down
Loading

0 comments on commit a84f437

Please sign in to comment.