-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.js
112 lines (91 loc) · 3.5 KB
/
handlers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
const ByteBuffer = require('bytebuffer');
const Long = require('long');
const SteamID = require('steamid');
const Underlords = require('./index.js');
const Language = require('./language.js');
const Protos = require('./protobufs/generated/_load.js');
let handlers = Underlords.prototype._handlers;
// ClientWelcome and ClientConnectionStatus
handlers[Language.ClientWelcome] = function(body) {
let proto = decodeProto(Protos.CMsgClientWelcome, body);
this.emit('debug', "GC connection established");
this.haveGCSession = true;
clearTimeout(this._helloTimer);
this._helloTimer = null;
this._helloTimerMs = 1000;
this.emit('connectedToGC');
};
handlers[Language.ClientConnectionStatus] = function(body) {
let proto = decodeProto(Protos.CMsgConnectionStatus, body);
this.emit('connectionStatus', proto.status, proto);
let statusStr = proto.status;
for (let i in Underlords.GCConnectionStatus) {
if (Underlords.GCConnectionStatus.hasOwnProperty(i) && Underlords.GCConnectionStatus[i] == proto.status) {
statusStr = i;
}
}
this.emit('debug', "Connection status: " + statusStr + " (" + proto.status + "); have session: " + (this.haveGCSession ? 'yes' : 'no'));
if (proto.status != Underlords.GCConnectionStatus.HAVE_SESSION && this.haveGCSession) {
this.emit('disconnectedFromGC', proto.status);
this.haveGCSession = false;
this._connect(); // Try to reconnect
}
};
// PlayersProfile
handlers[Language.GetProfileResponse] = function(body){
let proto = decodeProto(Protos.CMsgClientToGCGetProfileResponse, body);
this.emit('playersProfile', proto);
};
// MatchHistory
handlers[Language.GetMatchHistoryResponse] = function(body){
let proto = decodeProto(Protos.CMsgClientToGCGetMatchHistoryResponse, body);
this.emit('matchList', proto);
}
// Match Information
handlers[Language.GetProfileResponse] = function(body){
let proto = decodeProto(Protos.CMsgClientToGCGetProfileResponse, body);
this.emit('playersProfile', proto);
};
function decodeProto(proto, encoded) {
if (ByteBuffer.isByteBuffer(encoded)) {
encoded = encoded.toBuffer();
}
let decoded = proto.decode(encoded);
let objNoDefaults = proto.toObject(decoded, {"longs": String});
let objWithDefaults = proto.toObject(decoded, {"defaults": true, "longs": String});
return replaceDefaults(objNoDefaults, objWithDefaults);
function replaceDefaults(noDefaults, withDefaults) {
if (Array.isArray(withDefaults)) {
return withDefaults.map((val, idx) => replaceDefaults(noDefaults[idx], val));
}
for (let i in withDefaults) {
if (!withDefaults.hasOwnProperty(i)) {
continue;
}
if (withDefaults[i] && typeof withDefaults[i] === 'object' && !Buffer.isBuffer(withDefaults[i])) {
// Covers both object and array cases, both of which will work
// Won't replace empty arrays, but that's desired behavior
withDefaults[i] = replaceDefaults(noDefaults[i], withDefaults[i]);
} else if (typeof noDefaults[i] === 'undefined' && isReplaceableDefaultValue(withDefaults[i])) {
withDefaults[i] = null;
}
}
return withDefaults;
}
function isReplaceableDefaultValue(val) {
if (Buffer.isBuffer(val) && val.length == 0) {
// empty buffer is replaceable
return true;
}
if (Array.isArray(val)) {
// empty array is not replaceable (empty repeated fields)
return false;
}
if (val === '0') {
// Zero as a string is replaceable (64-bit integer)
return true;
}
// Anything falsy is true
return !val;
}
}