UNPKG

5.62 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 {
68 self._gc.send({msg: CSGO.EGCBaseClientMsg.k_EMsgGCClientHello, proto: {}},
69 new protos.CMsgClientHello({}).toBuffer());
70 }
71 };
72};
73util.inherits(CSGOClient, EventEmitter);
74
75CSGOClient.prototype.ServerRegion = CSGO.ServerRegion;
76CSGOClient.prototype.GameMode = CSGO.GameMode;
77
78CSGOClient.prototype.ToAccountID = function(accid){
79 return new bignumber(accid).minus('76561197960265728')-0;
80};
81
82CSGOClient.prototype.ToSteamID = function(accid){
83 return new bignumber(accid).plus('76561197960265728')+"";
84};
85
86// Methods
87CSGOClient.prototype.launch = function() {
88 /* Reports to Steam that we are running Counter-Strike: Global Offensive. Initiates communication with GC with EMsgGCClientHello */
89 if (this.debug) {
90 util.log("Launching CS:GO");
91 }
92 this._user.gamesPlayed({
93 games_played: [{
94 game_id: '730'
95 }]
96 });
97
98 // Keep knocking on the GCs door until it accepts us.
99 this._gcClientHelloIntervalId = setInterval(this._sendClientHello, 2500);
100};
101
102CSGOClient.prototype.exit = function() {
103 /* Reports to Steam we are not running any apps. */
104 if (this.debug) {
105 util.log("Exiting CS:GO");
106 }
107
108 /* stop knocking if exit comes before ready event */
109 if (this._gcClientHelloIntervalId) {
110 clearInterval(this._gcClientHelloIntervalId);
111 this._gcClientHelloIntervalId = null;
112 }
113 this._gcReady = false;
114 this._user.gamesPlayed({
115 games_played: [{}]
116 });
117
118 /* let everyone know we've exited */
119 this.emit("exited");
120};
121
122
123// Handlers
124
125var handlers = CSGOClient.prototype._handlers = {};
126
127handlers[CSGO.EGCBaseClientMsg.k_EMsgGCClientWelcome] = function clientWelcomeHandler(message) {
128 /* Response to our k_EMsgGCClientHello, now we can execute other GC commands. */
129
130 // Only execute if _gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'ready');
131 if (this._gcClientHelloIntervalId) {
132 clearInterval(this._gcClientHelloIntervalId);
133 this._gcClientHelloIntervalId = null;
134
135 if (this.debug) {
136 util.log("Received client welcome.");
137 }
138 this._gcReady = true;
139 this.emit("ready");
140 }
141};
142
143handlers[CSGO.EGCBaseClientMsg.k_EMsgGCClientConnectionStatus] = function gcClientConnectionStatus(message) {
144 /* Catch and handle changes in connection status, cuz reasons u know. */
145
146 var status = protos.CMsgConnectionStatus.decode(message).status;
147
148 switch (status) {
149 case CSGO.GCConnectionStatus.GCConnectionStatus_HAVE_SESSION:
150 if (this.debug) {
151 util.log("GC Connection Status regained.");
152 }
153
154 // Only execute if _gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'ready');
155 if (this._gcClientHelloIntervalId) {
156 clearInterval(this._gcClientHelloIntervalId);
157 this._gcClientHelloIntervalId = null;
158
159 this._gcReady = true;
160 this.emit("ready");
161 }
162 break;
163
164 default:
165 if (this.debug) {
166 util.log("GC Connection Status unreliable - " + status);
167 }
168
169 // Only execute if !_gcClientHelloIntervalID, otherwise it's already been handled (and we don't want to emit multiple 'unready');
170 if (!this._gcClientHelloIntervalId) {
171 this._gcClientHelloIntervalId = setInterval(this._sendClientHello, 2500); // Continually try regain GC session
172
173 this._gcReady = false;
174 this.emit("unready");
175 }
176 break;
177 }
178};
179
180CSGOClient.prototype.Rank = ranks.Rank;
181CSGOClient.prototype.Level = ranks.Level;
182
183CSGO.CSGOClient = CSGOClient;
184CSGO.SharecodeDecoder = require("./helpers/sharecode").SharecodeDecoder;
185
186require("./handlers/match");
187require("./handlers/player");
188require("./handlers/rich_presence");
189require("./handlers/items");