-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.js
346 lines (299 loc) · 10.3 KB
/
game.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
/*
Psi2d.
*/
"use strict";
(function(exports) {
var arandom = function(a) { return a[Math.floor((Math.random() * a.length))]; }
var elements = require('./www/level/elements')
var Clock = require('./www/level/elements').Clock
var utils = require('./www/level/utils');
/*
The Game class contains a level, the clients and other information to make it playable.
This class send level updates to all players and update the level according to players movements.
Note that the integrator is part of the level.
*/
function Game() {
this.now = new Date().getTime();
this.state = null;
this.gameStarted = false;
this.maxlag = 1500;
this.size = [8, 8]
this.code = null
this.trash = false
this.dt = null
this.poses = {} //reverse lookup of poisitions
this.servers = []
this.diff_time = null
this.clients = []
this.constructors = {}
Object.preventExtensions(this);
}
Game.prototype = {
//game time. Used for integration
t: function() {
return new Date().getTime() - this.now;
},
//initialise the game
//with a clock that expires after 10 minuts
//and ends the match
setState: function(state) {
state.isServer = true;
this.constructors = state.constructors
state.isClient = false;
state.elements[0].clocks.push(new Clock(function(e, game) {
game.finished = true;
}, state.time + state.maxTime))
//duration of this match
this.state = state;
},
broadcastEventExceptUID: function(update) {
//broadcast an event to all players connected to the game. except the player UID
//so if one player moves, onlt the other ones get the moving update.
this.clients.forEach(function(client) {
if (client.debugemit && client.player.uid != update.uid) client.debugemit('event', update)
});
},
broadcastEvent: function(update, force) {
if (force === undefined) force = false
var f = 'event'
var d = update
if (update[0] == 'newElement') {
f = update[0];
d = update[1];
if (!force) return
}
this.clients.forEach(function(client) {
if (client.debugemit) client.debugemit(f, d)
});
},
//simulate the level up to time `time`
simulateTo: function(time) {
var dt = this.state.dt
if (time < this.state.time) {
throw new Error(["we will not simulate to the past","time",time,"this.state.time",this.state.time]);
}
this.state.simulateTo(time);
console.log('Game to: ',time);
},
broadcastEventTo: function(update, uid) {
this.clients.forEach(function(client) {
if (client.debugemit && client.player.uid == uid) client.debugemit('event', update)
});
},
cloneState: function(time) {
return this.state.cloneState(this.constructors[this.state.cname])
},
//a new player entered the game
addPlayer: function(player) {
this.state.players.push(player)
var game = this.state
player.uid = this.state.nextUid();
console.log('adding player', player.uid, 'adding player')
game.broadcast.push({ //spread the information about the new player in the chat
c: player.name + ' joined the match'
})
},
}
function Interface(data) {
this.rooms_class = data
this.room_counter=0;
}
Interface.prototype = {
//user wants to join a random room
joinRandom: function(client, tank) {
var room = null;
console.log('joining a random room');
while(room==null){
let my_room = arandom(this.rooms_class.rooms);
if (my_room.trash==false){
room = my_room;
}
}
console.log('Room:', room.code);
tank.code = room.code //set the code of a random room
console.log('New player: ', tank);
this.joinRoom(client, tank) //join said room
},
// a new user joind the room
joinRoom: function(client, tank) {
//first search for the room with code tank.code
var server = null;
this.rooms_class.rooms.forEach(function(m) {
if (m.code == tank.code) {
server = m
}
});
if(server.trash){
client.debugemit('event', {alert:'Room in the process of being garbage collected. Try again.'})
return;
}
// create a websocket wrapper, for debug purposes
client.debugemit = function(a, b,c) {
this.myemit(a, b,c)
}
console.log('server is', tank.code, server.code);
if (server == null) {
client.debugemit('event', {
alert: 'invalid room name :(',
goHome: true
})
return;
}
try {
client.player = new server.constructors[tank.player]()
} catch (e) {
console.log('unable to create new player of class', tank.player, ' classes:', JSON.stringify(server.constructors))
return;
}
// if we could create the user, then set its properties
client.joined = true
client.player.name = tank.name
client.server = server
client.spawned = false
client.server.clients.push(client); //add this client to the clients in the match
server.addPlayer(client.player)
var t = client.server.t();
client.server.simulateTo(t);
var ora2 = client.server.t()
client.server.simulateTo(ora2)
// send the level data to the new player
client.debugemit('setLevel', {
this_state: server.state,
playeruid: client.player.uid,
dt: client.server.dt,
code:this.code,
time: server.state.time,
size: client.server.size,
}, false);
client.server.simulateTo( client.server.t());
},
//client asks for a list of objects whose UIDs are inside
//tank list
getObjects: function(client, tank) {
if (!client.joined) {
client.close();
return
}
var new_elements = [];
var game = client.server.state
if (tank===undefined || tank==null || tank.length===undefined){
client.debugemit('event',{alert: 'tank must be an array'});
return;
}
for (var i = 0; i < tank.length; i++) {
var e = game.getByUid(tank[i])
if (game.elements.indexOf(e) >= 0) {
client.debugemit('newElement', e)
};
if (game.players.indexOf(e) >= 0) {
client.debugemit('newPlayer', e)
};
}
},
//client request to spawn
spawn: function(client, tank) {
var server = client.server
if (!client.spawned) {
client.spawned = false
var game = client.server.state
var p = game.getByUid(client.player.uid);
game.spawn(p)
client.debugemit('event', p, false)
} else {
client.debugemit('event', { // if user ask for double-spawn maybe we should kick it
alert: "please stop it."
})
}
},
//client ping
ping: function(client, tank){
client.debugemit('pong', tank); //hopefully client set us the time and will do the difference
},
// client requests its own position
getPosition: function(client, tank2) {
console.log('');
if (!client.joined) {
client.close();
return
}
let server = client.server;
server.simulateTo( client.server.t());
let level = server.state;
var p0 = level.getByUid(client.player.uid);
if(p0){
client.debugemit('event', {uid:p0.uid, pos:p0.pos})
}
},
/*
client sent an update json of its properties (e.g. move left) inside tank2
*/
event: function(client, tank2) {
console.log('');
if (!client.joined) {
client.close();
return
}
let server = client.server;
let level = server.state;
var p0 = level.getByUid(client.player.uid);
if (p0!==undefined && p0.pos!=null && (isNaN(p0.pos[0])||isNaN(p0.pos[1]))){
console.log(player);
throw "event: pos is nan";
}
server.simulateTo( client.server.t());
console.log('uid:', client.player.uid,'alive?',p0.alive, 'respawns', p0.respawns, 'game time:', level.time, 'tank:',tank2);
level.broadcast = level.broadcast.filter(function(u) {
server.broadcastEvent(u, true);
return false;
})
if(p0.alive && p0.respawns==tank2.respawns){
p0.update(tank2);
tank2.uid = client.player.uid;
client.server.simulateTo( client.server.t());
server.broadcastEventExceptUID(tank2)
}
client.server.simulateTo( client.server.t());
level.broadcast = level.broadcast.filter(function(u) {
server.broadcastEvent(u, true);
return false;
})
/*
if the finished flag in level is raised
(from the Clock objects added in the creation of it)
we show the top 10 playersm kick everyone out
and start a new match
*/
if (level.finished) {
var state = []
var players = level.players.slice(0)
players.sort(function(p1, p2) {
return p1.points - p2.points
});
var top10players = players.slice(0, 10)
var str = 'Game finished\n'
str += 'Top 10 players:\n'
top10players.forEach(function(p) {
str += p.name + ' points:' + p.points + '\n'
});
str += '\n'
str += 'gg!\n'
str += '\n'
server.broadcastEvent({
alert: str,
goHome: true,
nocompress:true
})
server.clients.forEach(function(c) {
c.close();
});
server.servers.removeRoom(this.code)
this.room_counter+=1;
server.servers.addRoom('ciaoPippo'+this.room_counter.toString())
server.trash = true
}
console.log('');
}
};
exports.Game = Game
exports.Interface = Interface
})(typeof exports === 'undefined' ? this['server'] = {} : exports);