UNPKG

5.97 kBJavaScriptView Raw
1var EventEmitter = require('events').EventEmitter,
2 util = require("util"),
3 ranks = require("./helpers/ranks"),
4 protos = require("./helpers/protos"),
5 protoMask = 0x80000000,
6 bignumber = require("bignumber.js"),
7 CSGO = exports;
8
9require("./protos/messages");
10
11var CSGOClient = function CSGOClient(steamUser, steamGC, debug) {
12 EventEmitter.call(this);
13
14 this.debug = debug || false;
15 this._user = steamUser;
16 this._gc = steamGC;
17 this._appid = 730;
18 this.chatChannels = []; // Map channel names to channel data.
19 this._gcReady = false;
20 this._gcClientHelloIntervalId = null;
21
22 var self = this;
23 this._gc.on('message', function(type, message, callback) {
24 callback = callback || null;
25
26 var kMsg = type.msg & ~protoMask;
27 if (self.debug) {
28 util.log("CS:GO fromGC: " + kMsg); // TODO: Turn type-protoMask into key name.
29 }
30 if (kMsg in self._handlers) {
31 if (callback) {
32 self._handlers[kMsg].call(self, message, callback);
33 }
34 else {
35 self._handlers[kMsg].call(self, message);
36 }
37 }
38 else {
39 self.emit("unhandled", kMsg);
40 }
41 });
42
43 this._gc._client.on('message', function(type, message, callback) {
44 callback = callback || null;
45
46 var kMsg = type.msg & ~protoMask;
47 if (kMsg in self._handlers) {
48 if (callback) {
49 self._handlers[kMsg].call(self, message, callback);
50 }
51 else {
52 self._handlers[kMsg].call(self, message);
53 }
54 }
55 else {
56 self.emit("unhandled_steam", kMsg);
57 }
58 });
59
60 this._sendClientHello = function() {
61 if (self.debug) {
62 util.log("Sending ClientHello");
63 }
64 if (!self._gc) {
65 util.log("GC went missing");
66 }
67 else if (!self._gc._client || !self._gc._client._connection) {
68 util.log("GC Connection went missing, exiting");
69
70 self._gcReady = false;
71
72 if (self._gcClientHelloIntervalId) {
73 clearInterval(self._gcClientHelloIntervalId);
74 self._gcClientHelloIntervalId = null;
75 }
76
77 self.emit("unready");
78 }
79 else {
80 self._gc.send({msg: CSGO.EGCBaseClientMsg.k_EMsgGCClientHello, proto: {}},
81 new protos.CMsgClientHello({}).toBuffer());
82 }
83 };
84};
85util.inherits(CSGOClient, EventEmitter);
86
87CSGOClient.prototype.ServerRegion = CSGO.ServerRegion;
88CSGOClient.prototype.GameMode = CSGO.GameMode;
89
90CSGOClient.prototype.ToAccountID = function(accid){
91 return new bignumber(accid).minus('76561197960265728')-0;
92};
93
94CSGOClient.prototype.ToSteamID = function(accid){
95 return new bignumber(accid).plus('76561197960265728')+"";
96};
97
98// Methods
99CSGOClient.prototype.launch = function() {
100 /* Reports to Steam that we are running Counter-Strike: Global Offensive. Initiates communication with GC with EMsgGCClientHello */
101 if (this.debug) {
102 util.log("Launching CS:GO");
103 }
104 this._user.gamesPlayed({
105 games_played: [{
106 game_id: '730'
107 }]
108 });
109
110 // Keep knocking on the GCs door until it accepts us.
111 this._gcClientHelloIntervalId = setInterval(this._sendClientHello, 2500);
112};
113
114CSGOClient.prototype.exit = function() {
115 /* Reports to Steam we are not running any apps. */
116 if (this.debug) {
117 util.log("Exiting CS:GO");
118 }
119
120 /* stop knocking if exit comes before ready event */
121 if (this._gcClientHelloIntervalId) {
122 clearInterval(this._gcClientHelloIntervalId);
123 this._gcClientHelloIntervalId = null;
124 }
125 this._gcReady = false;
126 this._user.gamesPlayed({
127 games_played: [{}]
128 });
129
130 /* let everyone know we've exited */
131 this.emit("exited");
132};
133
134
135// Handlers
136
137var handlers = CSGOClient.prototype._handlers = {};
138
139handlers[CSGO.EGCBaseClientMsg.k_EMsgGCClientWelcome] = function clientWelcomeHandler(message) {
140 /* Response to our k_EMsgGCClientHello, now we can execute other GC commands. */
141
142 // Only execute if _gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'ready');
143 if (this._gcClientHelloIntervalId) {
144 clearInterval(this._gcClientHelloIntervalId);
145 this._gcClientHelloIntervalId = null;
146
147 if (this.debug) {
148 util.log("Received client welcome.");
149 }
150 this._gcReady = true;
151 this.emit("ready");
152 }
153};
154
155handlers[CSGO.EGCBaseClientMsg.k_EMsgGCClientConnectionStatus] = function gcClientConnectionStatus(message) {
156 /* Catch and handle changes in connection status, cuz reasons u know. */
157
158 var status = protos.CMsgConnectionStatus.decode(message).status;
159
160 switch (status) {
161 case CSGO.GCConnectionStatus.GCConnectionStatus_HAVE_SESSION:
162 if (this.debug) {
163 util.log("GC Connection Status regained.");
164 }
165
166 // Only execute if _gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'ready');
167 if (this._gcClientHelloIntervalId) {
168 clearInterval(this._gcClientHelloIntervalId);
169 this._gcClientHelloIntervalId = null;
170
171 this._gcReady = true;
172 this.emit("ready");
173 }
174 break;
175
176 default:
177 if (this.debug) {
178 util.log("GC Connection Status unreliable - " + status);
179 }
180
181 // Only execute if !_gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'unready');
182 if (!this._gcClientHelloIntervalId) {
183 this._gcClientHelloIntervalId = setInterval(this._sendClientHello, 2500); // Continually try regain GC session
184
185 this._gcReady = false;
186 this.emit("unready");
187 }
188 break;
189 }
190};
191
192CSGOClient.prototype.Rank = ranks.Rank;
193CSGOClient.prototype.Level = ranks.Level;
194
195CSGO.CSGOClient = CSGOClient;
196CSGO.SharecodeDecoder = require("./helpers/sharecode").SharecodeDecoder;
197
198require("./handlers/match");
199require("./handlers/player");
200require("./handlers/rich_presence");
201require("./handlers/items");