-
Notifications
You must be signed in to change notification settings - Fork 0
/
vwf_client_sim.js
430 lines (354 loc) · 11.5 KB
/
vwf_client_sim.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
var http = require("http");
var fs = require('fs');
var url = require("url");
var mime = require('mime');
var io = require('socket.io-client');
var CryptoJS = require('cryptojs');
function GUID()
{
var S4 = function ()
{
return Math.floor(
Math.random() * 0x10000 /* 65536 */
).toString(16);
};
return (
S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4()
);
}
var EncryptPassword = function (password, username,salt)
{
console.log(password,username,salt);
var unencrpytedpassword = password + username + salt;
for (var i = 0; i < 1000; i++)
{
unencrpytedpassword = CryptoJS.Crypto.SHA256(unencrpytedpassword) + '';
}
return unencrpytedpassword;
}
function LaunchAvatar(username_in,password_in,server_in,port_in,session_in)
{
var username = username_in;
var passwordHASH;
var password = password_in;
var session = session_in;
var socket;
var socketid;
var server = server_in;
var port = port_in;
var currenttime = 0;
// some #defines for readability
var UP =0;
var DOWN = 1;
var salt;
process.on('exit', function() {
socket.disconnect();
});
var stdin = process.openStdin();
stdin.on('data', function(chunk) {
if(!chunk) return;
chunk = chunk + '';
chunk = chunk.replace(/\r\n/g,'');
if(chunk == 'quit')
process.exit();
});
console.log('Launching Avatar at ' + server +':'+port+' with username: ' + username +' and password: ' + password+' in world '+session);
//quick macro to send a message
function send(data)
{
socket.emit('message',JSON.stringify(data));
}
//generate a key event and send it
// State is either UP or DOWN, key is a char
function KeyEvent(state,key)
{
key = key.toUpperCase()[0];
//the proper keyevent message
var keyevent = {"time": currenttime,
"node": "index-vwf",
"action": "dispatchEvent",
"member": (state == UP ? 'keyUp' : 'keyDown'), //key up or key down
"parameters": [
[
{
"keysDown": {},
"mods": {
"alt": false,
"shift": false,
"ctrl": false,
"meta": false
},
"keysUp": {}
}
],
null
],
"client": socketid}
keyevent.parameters[0][0][state == UP ? 'keysUp' : 'keysDown'][key] = {
"key": key,
"code": key.charCodeAt(0),
"char": key
}
//send the event
send(keyevent);
}
//once the entire login procedure is done, we can start sending commands over the socket
worldLoginComplete = function(response) {
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log(str);
//we are finally done logging in, so let's send the avatar object over the socket to be created
//The object below is the proper defination of an avatar
var component =
{
"time": currenttime,
"node": "index-vwf",
"action": "createChild",
"member": username,
"parameters": [
{
"extends": "character.vwf",
"source": "usmale.dae",
"type": "subDriver/threejs/asset/vnd.collada+xml",
"properties": {
"PlayerNumber": username, //make it look like the user we logged in as is the owner of the avatar
"owner": username,
"ownerClientID": socket.socket.sessionid, //this lets the avatar know which socket controlls it
"profile": {
"Username": username,
"Name": "TEST AVATAR",
"Age": "32",
"Birthday": "",
"Password": "",
"Relationship": "Married",
"City": "Mclean",
"State": "VA",
"Homepage": "",
"Employer": "ADL",
"Title": "",
"Height": "",
"Weight": "",
"Nationality": "",
"Avatar": "usmale.dae",
"inventoryKey": "1komqvgn",
"password": ""
},
"translation": [ //we randomly place him in the world center +-5
(Math.random() - .5) * 5,
(Math.random() - .5) * 5,
0
]
},
"events": {
"ShowProfile": null,
"Message": null
},
"scripts": [
"this.ShowProfile = function(){if(vwf.client() != vwf.moniker()) return; _UserManager.showProfile(_DataManager.GetProfileForUser(this.PlayerNumber)) }; \nthis.Message = function(){if(vwf.client() != vwf.moniker()) return; setupPmWindow(this.PlayerNumber) }"
]
}
]
}
console.log('sending avatar');
socket.emit('message',JSON.stringify(component));
});
}
//here, we handle incomming data from the server
function OnMessage(data)
{
//keep track of the server time pulse
currenttime = data.time;
//if we are keeping track of state and the server requests it, send it
if(data.action == 'getState')
{
send({action:'getState','parameters':[],'result':{nodes:[global.state],queue:[]} || {}});
}
//if the server sends is world state, keep track of it
if(data.action == 'createNode')
{
global.state = data.parameters[0];
console.log(global.state);
}
if(data.action == 'createChild')
{
console.log(data);
var childComponent = JSON.parse(JSON.stringify(data.parameters[0]));
if(!childComponent) return;
var childName = data.member;
if(!childName) return;
var childID = childComponent.id || childComponent.uri || ( childComponent["extends"] ) + "." + childName.replace(/ /g,'-');
childID = childID.replace( /[^0-9A-Za-z_]+/g, "-" );
if(!global.state.children)
global.state.children={};
global.state.children[childID] = childComponent;
}
if(data.action == 'setState')
{
global.state = data.parameters[0].nodes[0];
console.log(global.state);
}
//Here is the real meat of the simulation.
//This bot randomly hits the keys, and the avatar will move.
if(data.action == 'tick')
{
var rnd = Math.floor(Math.random() * 100)
if(rnd == 0)
{
KeyEvent(DOWN,'w');
}
if(rnd == 1)
{
KeyEvent(UP,'w');
}
if(rnd == 2)
{
KeyEvent(DOWN,'s');
}
if(rnd == 3)
{
KeyEvent(UP,'s');
}
if(rnd == 4)
{
KeyEvent(DOWN,'z');
}
if(rnd == 5)
{
KeyEvent(UP,'z');
}
if(rnd == 6)
{
KeyEvent(DOWN,'c');
}
if(rnd == 7)
{
KeyEvent(UP,'c');
}
}
} //end onMessage
//now that we know the session cookie, we can call the world login endpoint
function connectSocket(cookie)
{
//first, we connect the websocket to the server
socket = io.connect('http://'+server+':'+port+'/');
//we need to know this so we can tell the server that the user with the given session cookie ownes the socket
socketid = socket.socket.sessionid;
//link up the handler for the incomming data
socket.on('message', function (data) {
OnMessage(data);
});
//now that we have set the socket to the world, tell the server that the user at the session cookie are the owner of this socket
socket.on('namespaceSet', function (data) {
console.log(socket.socket.sessionid);
//we now must use an http request to tell the server that 'we' own the socket.
//'we' meaning the user logged into the client with the given session cookie
//goto worldLoginComplete when done
var req = http.request({hostname:server,port:port,method:'GET', path:'/adl/sandbox///vwfDataManager.svc/login?S='+session+'&CID=' + socket.socket.sessionid,headers:{cookie:cookie}}, worldLoginComplete).end();
});
//This is a special case for the simulated client
//we must ask the server to associate this websocket with a the given world
//when complete, the server will call namespaceSet
socket.emit('setNamespace', { space: session });
}
//we get here after the client has submitted the username and password properly to the server
siteLoginComplete = function(response) {
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log(str);
//this is the session cookie for the client. It identifies that this client has session on the server
console.log(response.headers['set-cookie']);
//the server sends a session ID to the client. We need to remember this to log into the world
connectSocket(response.headers['set-cookie']);
});
}
//after we have the salt for the user, we can create the proper username/password hash to log in
saltRetreiveComplete = function(response) {
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log('salt: '+str);
salt = str.trim();
//create the proper hash for the password, and try to loging this client to the server
//when complete, goto siteLoginComplete
passwordHASH = EncryptPassword(password,username,salt);
http.request('http://'+server+':'+port+'/vwfDataManager.svc/sitelogin?UID='+username+'&P='+passwordHASH, siteLoginComplete).end();
});
}
var postdata;
function SignupPostCompete(response)
{
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log(str);
//boot up the whole client, start by getting the hash for this user
//when complete, goto saltRetreiveComplete
http.request('http://'+server+':'+port+'/vwfDataManager.svc/salt?UID='+username, saltRetreiveComplete).end();
});
}
function Signup()
{
var salt = GUID();
var enc_password = EncryptPassword(password,username,salt);
var profile = {};
profile.Username = username;
profile.Password = enc_password;
profile.Avatar = 'usmale.dae';
profile.Salt = salt;
postdata = JSON.stringify(profile);
var options = {
hostname : server,
port : port,
path : '/vwfDataManager.svc/CreateProfile?UID='+username+ "&P=" +enc_password,
method: 'POST'
};
var req = http.request(options, SignupPostCompete);
req.write(postdata);
req.end();
}
Signup();
}
// -u is the username of the account to use
var p = process.argv.indexOf('-u');
var user = p >= 0 ? process.argv[p+1] : "test";
// -p is the password
p = process.argv.indexOf('-p');
var password = p >= 0 ? process.argv[p+1] : "1111";
// -s the name of the server to connect to
p = process.argv.indexOf('-s');
var server = p >= 0 ? process.argv[p+1] : "localhost";
// -t is the port to use on the server
p = process.argv.indexOf('-t');
var port = p >= 0 ? process.argv[p+1] : "3000";
// -w is the UID of the world to attach to
p = process.argv.indexOf('-w');
var world = p >= 0 ? process.argv[p+1] : "QNsNId8RYKeO6MSz";
//launch the simulated client
LaunchAvatar(user,password,server,port,"/adl/sandbox/" + world + "/");
process.on('message', function(m) {
console.log('CHILD got message:', m);
if(m == 'kill')
process.exit();
});