-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.server.js
380 lines (328 loc) · 14.6 KB
/
game.server.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
/* Copyright (c) 2012 Sven "FuzzYspo0N" Bergström, 2013 Robert XD Hawkins
written by : http://underscorediscovery.com
written for : http://buildnewgames.com/real-time-multiplayer/
modified for collective behavior experiments on Amazon Mechanical Turk
MIT Licensed.
*/
//require('look').start()
var
use_db = false,
game_server = module.exports = { games : {}, game_count:0, assignment:0},
fs = require('fs');
if (use_db) {
database = require(__dirname + "/database"),
connection = database.getConnection();
}
global.window = global.document = global;
require('./game.core.js');
utils = require('./utils.js');
var moveObject = function(client, i, x, y) {
var obj = client.game.gamecore.objects[i]
var others = client.game.gamecore.get_others(client.userid);
obj.trueX = parseInt(x)
obj.trueY = parseInt(y)
var cell = client.game.gamecore.getCellFromPixel(obj.trueX, obj.trueY)
obj.lastX = cell[0]
obj.lastY = cell[1]
_.map(others, function(p) {
p.player.instance.emit('objMove', {i: i, x: x, y: y})
})
}
// This is the function where the server parses and acts on messages
// sent from 'clients' aka the browsers of people playing the
// game. For example, if someone clicks on the map, they send a packet
// to the server (check the client_on_click function in game.client.js)
// with the coordinates of the click, which this function reads and
// applies.
game_server.server_onMessage = function(client,message) {
//Cut the message up into sub components
var message_parts = message.split('.');
//The first is always the type of message
var message_type = message_parts[0];
//Extract important variables
var gc = client.game.gamecore
var id = gc.instance.id.slice(0,6)
var all = gc.get_active_players();
var target = gc.get_player(client.userid);
var others = gc.get_others(client.userid);
switch(message_type) {
case 'objMove' : // Client is changing angle
moveObject(client, message_parts[1], message_parts[2], message_parts[3])
break;
case 'correctDrop' :
moveObject(client, message_parts[1], message_parts[2], message_parts[3])
gc.attemptNum = 0;
_.map(all, function(p) {p.player.instance.send("s.waiting.correct")})
gc.paused = true;
break;
case 'incorrectDrop' :
writeData(client, "error", message_parts)
moveObject(client, message_parts[1], message_parts[2], message_parts[3])
gc.paused = true;
gc.attemptNum += 1;
_.map(all, function(p) {p.player.instance.send("s.waiting.incorrect") })
break;
case 'waitCheck':
//writeData(client, "error", message_parts)
gc.paused = true;
gc.attemptNum += 1;
_.map(all, function (p) { p.player.instance.send("s.waitCheck.wait") })
break;
case 'checkMessage':
//writeData(client, "error", message_parts)
check_res = message_parts[2];
gc.paused = true;
_.map(all, function (p) { p.player.instance.send("s.waiting." + check_res) })
break;
case 'ready' :
gc.paused = false
new_round = true
if(message_parts[1] === "incorrect")
gc.instructionNum -= 1
//if (client.game.gamecore.instructionNum + 1 < client.game.gamecore.instructions.length)
//check if the game is finished
if(client.game.gamecore.objects.length > 0){
//the game is started
//sort the three items
x_array = new Array()
y_array = new Array()
tmp = -1
for(j = 0; j < client.game.gamecore.objects.length; j++){
x_array[j] = client.game.gamecore.objects[j].lastX
y_array[j] = client.game.gamecore.objects[j].lastY
}
if (x_array[0] > x_array[1]) {
tmp = x_array[0]
x_array[0] = x_array[1]
x_array[1] = tmp
tmp = y_array[0]
y_array[0] = y_array[1]
y_array[1] = tmp
}
if (x_array[0] > x_array[2]) {
tmp = x_array[0]
x_array[0] = x_array[2]
x_array[2] = tmp
tmp = y_array[0]
y_array[0] = y_array[2]
y_array[2] = tmp
}
if (x_array[1] > x_array[2]) {
tmp = x_array[1]
x_array[1] = x_array[2]
x_array[2] = tmp
tmp = y_array[1]
y_array[1] = y_array[2]
y_array[2] = tmp
}
//the condition of game over
console.log(x_array)
console.log(y_array)
if ( x_array[0] == 4 && y_array[0] == 1 &&
x_array[1] == 5 && y_array[1] == 3 &&
x_array[2] == 5 && y_array[2] == 2
){
//game over
new_round = true
}
else{
new_round = false
}
}else{
//the game is not started
new_round = true
}
if(!new_round)
gc.newInstruction();
else
gc.newRound();
break;
case 'chatMessage' :
//write data to file
if(client.game.player_count == 2 && !gc.paused)
writeData(client, "message", message_parts)
// Update others
var msg = message_parts[2].replace(/-/g,'.')
_.map(all, function(p){
p.player.instance.emit( 'chatMessage', {user: client.userid, msg: msg})})
break;
case 'update_mouse' :
// write data to file
if(!gc.paused)
writeData(client, "mouse", message_parts)
break;
case 'h' : // Receive message when browser focus shifts
target.visible = message_parts[1];
break;
}
};
var writeData = function(client, type, message_parts) {
var gc = client.game.gamecore
var attemptNum = gc.attemptNum;
var condition = gc.trialList[0].condition
var objectSet = gc.trialList[0].objectSet
var instructionNum = gc.instructionNum
var object_name = gc.instructions[gc.instructionNum].split(' ')[0]
var object = _.find(gc.objects, function (obj) { return obj.name == object_name })
var critical = object.critical === "filler" ? 0 : 1
var id = gc.instance.id.slice(0,6)
switch(type) {
case "mouse" :
var date = message_parts[1]
var x = message_parts[2]
var y = message_parts[3]
if(object.critical === "filler") {
var distractorX = "none"
var distractorY = "none"
} else {
var distractor = _.find(gc.objects, function(obj) { return obj.critical == "distractor" })
var distractorX = distractor.trueX + distractor.width/2
var distractorY = distractor.trueY + distractor.height/2
}
var objX = object.trueX + object.width/2
var objY = object.trueY + object.height/2
var line = String(id + ',' + date + ',' + condition + ',' + critical + ',' +
objectSet + ',' + instructionNum + ',' + attemptNum + ',' + objX + ',' + objY + ',' +
distractorX + ',' + distractorY + ',' + x + ',' + y ) + "\n"
//console.log("mouse:" + line)
gc.mouseDataStream.write(line, function (err) {if(err) throw err;});
break;
case "message" :
var date = message_parts[1]
var msg = message_parts[2].replace(/-/g,'.')
var line = (id + ',' + date + ',' + condition + ',' + critical + ',' +
objectSet + ',' + instructionNum + ',' + attemptNum + ',' + client.role + ',"' + msg + '"\n')
console.log("message:" + line)
gc.messageStream.write(line);
break;
case "error" :
var trueItem = gc.instructions[gc.instructionNum].split(' ')[0]
var line = (id + ',' + String(message_parts[6]) + ',' + condition + ','
+ critical + ',' + objectSet + ',' + instructionNum + ','
+ attemptNum + ',' +trueItem + ','
+ gc.objects[message_parts[1]].name + ','
+ parseInt(gc.currentDestination[0]) + ','
+ parseInt(gc.currentDestination[1]) + ','
+ parseInt(message_parts[4]) + ',' + parseInt(message_parts[5]) + '\n')
console.log("incorrect: ", line);
gc.errorStream.write(line)
break;
}
}
/*
The following functions should not need to be modified for most purposes
*/
// This is the important function that pairs people up into 'rooms'
// all independent of one another.
game_server.findGame = function(player) {
this.log('looking for a game. We have : ' + this.game_count);
//if there are any games created, add this player to it!
if(this.game_count) {
var joined_a_game = false;
for (var gameid in this.games) {
if(!this.games.hasOwnProperty(gameid)) continue;
var game = this.games[gameid];
var gamecore = game.gamecore;
if(game.player_count < gamecore.players_threshold) {
joined_a_game = true;
// player instances are array of actual client handles
game.player_instances.push({
id: player.userid,
player: player
});
game.player_count++;
// players are array of player objects
game.gamecore.players.push({
id: player.userid,
player: new game_player(gamecore,player)
});
// Establish write streams
var d = new Date();
var start_time = d.getFullYear() + '-' + d.getMonth() + 1 + '-' + d.getDate() + '-' + d.getHours() + '-' + d.getMinutes() + '-' + d.getSeconds() + '-' + d.getMilliseconds()
var name = start_time + '_' + game.id;
var mouse_f = "data/mouse/" + name + ".csv"
fs.writeFile(mouse_f, "gameid, time, condition, critical, objectSet, instructionNum, attemptNum, targetX, targetY, distractorX, distractorY, mouseX, mouseY\n", function (err) {if(err) throw err;})
game.gamecore.mouseDataStream = fs.createWriteStream(mouse_f, {'flags' : 'a'});
var error_f = "data/error/" + name + ".csv"
fs.writeFile(error_f, "gameid, time, condition, critical, objectSet, instructionNum, attemptNum, intendedObj, actualObj, intendedX, intendedY, actualX, actualY\n", function (err) {if(err) throw err;})
game.gamecore.errorStream = fs.createWriteStream(error_f, {'flags' : 'a'});
var message_f = "data/message/" + name + ".csv"
fs.writeFile(message_f, "gameid, time, condition, critical, objectSet, instructionNum, attemptNum, sender, contents\n", function (err) {if(err) throw err;})
game.gamecore.messageStream = fs.createWriteStream(message_f, {'flags' : 'a'});
// console.log('game ' + game.id + ' starting with ' + game.player_count + ' players...')
// Attach game to player so server can look at it later
player.game = game;
player.role = 'matcher';
// notify new player that they're joining game
player.send('s.join.' + gamecore.players.length + '.' + player.role)
// notify existing players that someone new is joining
_.map(gamecore.get_others(player.userid),
function(p){p.player.instance.send( 's.add_player.' + player.userid)})
gamecore.server_send_update()
_.map(gamecore.get_active_players(), function(p) {
p.player.instance.send("s.waiting")
})
gamecore.player_count = game.player_count;
}
}
if(!joined_a_game) { // if we didn't join a game, we must create one
this.createGame(player);
}
}
else {
//no games? create one!
this.createGame(player);
}
};
// Will run when first player connects
game_server.createGame = function(player) {
var players_threshold = 2
var d = new Date();
var start_time = d.getFullYear() + '-' + d.getMonth() + 1 + '-' + d.getDate() + '-' + d.getHours() + '-' + d.getMinutes() + '-' + d.getSeconds() + '-' + d.getMilliseconds()
var gameID = utils.UUID();
var name = start_time + '_' + gameID;
//Create a new game instance
var game = {
//generate a new id for the game
id : gameID,
//store list of players in the game
player_instances: [{id: player.userid, player: player}],
//for simple checking of state
player_count: 1
};
//Create a new game core instance (defined in game.core.js)
game.gamecore = new game_core(game);
// Tell the game about its own id
game.gamecore.game_id = gameID;
game.gamecore.players_threshold = players_threshold
game.gamecore.player_count = 1
// assign role
player.game = game;
player.role = 'director';
player.send('s.join.' + game.gamecore.players.length + '.' + player.role)
this.log('player ' + player.userid + ' created a game with id ' + player.game.id);
// add to game collection
this.games[ game.id ] = game;
this.game_count++;
game.gamecore.server_send_update()
return game;
};
// we are requesting to kill a game in progress.
// This gets called if someone disconnects
game_server.endGame = function(gameid, userid) {
var thegame = this.games [ gameid ];
if(thegame) {
_.map(thegame.gamecore.get_others(userid), function(p) {
p.player.instance.send('s.end');})
delete this.games[gameid];
this.game_count--;
this.log('game removed. there are now ' + this.game_count + ' games' );
} else {
this.log('that game was not found!');
}
};
//A simple wrapper for logging so we can toggle it,
//and augment it for clarity.
game_server.log = function() {
console.log.apply(this,arguments);
};