Cube  Diff

Differences From Artifact [133bbad38c]:

To Artifact [2b7d5c9bfe]:


36
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
restoreserverstate(
    vector<entity> &ents) // hack: called from savegame code, only works in SP
{
	loopv(sents)
	{
		sents[i].spawned = ents[i].spawned;
		sents[i].spawnsecs = 0;
	};
};



int interm = 0, minremain = 0, mapend = 0;
bool mapreload = false;

static OFString *serverpassword = @"";

bool isdedicated;







<
<
>
>







36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
restoreserverstate(
    vector<entity> &ents) // hack: called from savegame code, only works in SP
{
	loopv(sents)
	{
		sents[i].spawned = ents[i].spawned;
		sents[i].spawnsecs = 0;


	}
}

int interm = 0, minremain = 0, mapend = 0;
bool mapreload = false;

static OFString *serverpassword = @"";

bool isdedicated;
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
		break;
	};

	case ST_LOCAL:
		localservertoclient(packet->data, packet->dataLength);
		break;
	};
};


void
send2(bool rel, int cn, int a, int b)
{
	ENetPacket *packet =
	    enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0);
	uchar *start = packet->data;
	uchar *p = start + 2;
	putint(p, a);
	putint(p, b);
	*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
	enet_packet_resize(packet, p - start);
	if (cn < 0)
		process(packet, -1);
	else
		send(cn, packet);
	if (packet->referenceCount == 0)
		enet_packet_destroy(packet);
};


void
sendservmsg(OFString *msg)
{
	ENetPacket *packet = enet_packet_create(
	    NULL, _MAXDEFSTR + 10, ENET_PACKET_FLAG_RELIABLE);
	uchar *start = packet->data;







<
>


















<
>







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
		break;
	};

	case ST_LOCAL:
		localservertoclient(packet->data, packet->dataLength);
		break;
	};

}

void
send2(bool rel, int cn, int a, int b)
{
	ENetPacket *packet =
	    enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0);
	uchar *start = packet->data;
	uchar *p = start + 2;
	putint(p, a);
	putint(p, b);
	*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
	enet_packet_resize(packet, p - start);
	if (cn < 0)
		process(packet, -1);
	else
		send(cn, packet);
	if (packet->referenceCount == 0)
		enet_packet_destroy(packet);

}

void
sendservmsg(OFString *msg)
{
	ENetPacket *packet = enet_packet_create(
	    NULL, _MAXDEFSTR + 10, ENET_PACKET_FLAG_RELIABLE);
	uchar *start = packet->data;
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
void
disconnect_client(int n, char *reason)
{
	printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason);
	enet_peer_disconnect(clients[n].peer);
	clients[n].type = ST_EMPTY;
	send2(true, -1, SV_CDIS, n);
};


void
resetitems()
{
	sents.setsize(0);
	notgotitems = true;
};


void
pickup(uint i, int sec, int sender) // server side item pickup, acknowledge
                                    // first client that gets it
{
	if (i >= (uint)sents.length())
		return;
	if (sents[i].spawned) {
		sents[i].spawned = false;
		sents[i].spawnsecs = sec;
		send2(true, sender, SV_ITEMACC, i);
	};
};


void
resetvotes()
{
	loopv(clients) clients[i].mapvote[0] = 0;
};


bool
vote(char *map, int reqmode, int sender)
{
	strcpy_s(clients[sender].mapvote, map);
	clients[sender].modevote = reqmode;
	int yes = 0, no = 0;
	loopv(clients) if (clients[i].type != ST_EMPTY)
	{
		if (clients[i].mapvote[0]) {
			if (strcmp(clients[i].mapvote, map) == 0 &&
			    clients[i].modevote == reqmode)
				yes++;
			else
				no++;
		} else
			no++;
	};

	if (yes == 1 && no == 0)
		return true; // single player
	@autoreleasepool {
		OFString *msg =
		    [OFString stringWithFormat:
		                  @"%s suggests %@ on map %s (set map to vote)",
		              clients[sender].name, modestr(reqmode), map];
		sendservmsg(msg);
	}
	if (yes / (float)(yes + no) <= 0.5f)
		return false;
	sendservmsg(@"vote passed");
	resetvotes();
	return true;
};


// server side processing of updates: does very little and most state is tracked
// client only could be extended to move more gameplay to server (at expense of
// lag)

void
process(ENetPacket *packet, int sender) // sender may be -1







<
>






<
>












<
>





<
>

















<
>














<
>







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
void
disconnect_client(int n, char *reason)
{
	printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason);
	enet_peer_disconnect(clients[n].peer);
	clients[n].type = ST_EMPTY;
	send2(true, -1, SV_CDIS, n);

}

void
resetitems()
{
	sents.setsize(0);
	notgotitems = true;

}

void
pickup(uint i, int sec, int sender) // server side item pickup, acknowledge
                                    // first client that gets it
{
	if (i >= (uint)sents.length())
		return;
	if (sents[i].spawned) {
		sents[i].spawned = false;
		sents[i].spawnsecs = sec;
		send2(true, sender, SV_ITEMACC, i);
	};

}

void
resetvotes()
{
	loopv(clients) clients[i].mapvote[0] = 0;

}

bool
vote(char *map, int reqmode, int sender)
{
	strcpy_s(clients[sender].mapvote, map);
	clients[sender].modevote = reqmode;
	int yes = 0, no = 0;
	loopv(clients) if (clients[i].type != ST_EMPTY)
	{
		if (clients[i].mapvote[0]) {
			if (strcmp(clients[i].mapvote, map) == 0 &&
			    clients[i].modevote == reqmode)
				yes++;
			else
				no++;
		} else
			no++;

	}
	if (yes == 1 && no == 0)
		return true; // single player
	@autoreleasepool {
		OFString *msg =
		    [OFString stringWithFormat:
		                  @"%s suggests %@ on map %s (set map to vote)",
		              clients[sender].name, modestr(reqmode), map];
		sendservmsg(msg);
	}
	if (yes / (float)(yes + no) <= 0.5f)
		return false;
	sendservmsg(@"vote passed");
	resetvotes();
	return true;

}

// server side processing of updates: does very little and most state is tracked
// client only could be extended to move more gameplay to server (at expense of
// lag)

void
process(ENetPacket *packet, int sender) // sender may be -1
299
300
301
302
303
304
305
306

307
308
309
310
311
312
313
		};

	if (p > end) {
		disconnect_client(sender, "end of packet");
		return;
	};
	multicast(packet, sender);
};


void
send_welcome(int n)
{
	ENetPacket *packet =
	    enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
	uchar *start = packet->data;







<
>







299
300
301
302
303
304
305

306
307
308
309
310
311
312
313
		};

	if (p > end) {
		disconnect_client(sender, "end of packet");
		return;
	};
	multicast(packet, sender);

}

void
send_welcome(int n)
{
	ENetPacket *packet =
	    enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
	uchar *start = packet->data;
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
multicast(ENetPacket *packet, int sender)
{
	loopv(clients)
	{
		if (i == sender)
			continue;
		send(i, packet);
	};
};



void
localclienttoserver(ENetPacket *packet)
{
	process(packet, 0);
	if (!packet->referenceCount)
		enet_packet_destroy(packet);
};


client &
addclient()
{
	loopv(clients) if (clients[i].type == ST_EMPTY) return clients[i];
	return clients.add();
};


void
checkintermission()
{
	if (!minremain) {
		interm = lastsec + 10;
		mapend = lastsec + 1000;
	};
	send2(true, -1, SV_TIMEUP, minremain--);
};


void
startintermission()
{
	minremain = 0;
	checkintermission();
};


void
resetserverifempty()
{
	loopv(clients) if (clients[i].type != ST_EMPTY) return;
	clients.setsize(0);
	smapname = @"";







<
<
>
>







<
>






<
>









<
>






<
>







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
multicast(ENetPacket *packet, int sender)
{
	loopv(clients)
	{
		if (i == sender)
			continue;
		send(i, packet);


	}
}

void
localclienttoserver(ENetPacket *packet)
{
	process(packet, 0);
	if (!packet->referenceCount)
		enet_packet_destroy(packet);

}

client &
addclient()
{
	loopv(clients) if (clients[i].type == ST_EMPTY) return clients[i];
	return clients.add();

}

void
checkintermission()
{
	if (!minremain) {
		interm = lastsec + 10;
		mapend = lastsec + 1000;
	};
	send2(true, -1, SV_TIMEUP, minremain--);

}

void
startintermission()
{
	minremain = 0;
	checkintermission();

}

void
resetserverifempty()
{
	loopv(clients) if (clients[i].type != ST_EMPTY) return;
	clients.setsize(0);
	smapname = @"";
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
431
432
	{
		if (sents[i].spawnsecs &&
		    (sents[i].spawnsecs -= seconds - lastsec) <= 0) {
			sents[i].spawnsecs = 0;
			sents[i].spawned = true;
			send2(true, -1, SV_ITEMSPAWN, i);
		};
	};


	lastsec = seconds;

	if ((mode > 1 || (mode == 0 && nonlocalclients)) &&
	    seconds > mapend - minremain * 60)
		checkintermission();
	if (interm && seconds > interm) {
		interm = 0;
		loopv(clients) if (clients[i].type != ST_EMPTY)
		{
			send2(true, i, SV_MAPRELOAD,
			    0); // ask a client to trigger map reload
			mapreload = true;
			break;
		};

	};

	resetserverifempty();

	if (!isdedicated)
		return; // below is network only








<
>














<
>







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
431
432
	{
		if (sents[i].spawnsecs &&
		    (sents[i].spawnsecs -= seconds - lastsec) <= 0) {
			sents[i].spawnsecs = 0;
			sents[i].spawned = true;
			send2(true, -1, SV_ITEMSPAWN, i);
		};

	}

	lastsec = seconds;

	if ((mode > 1 || (mode == 0 && nonlocalclients)) &&
	    seconds > mapend - minremain * 60)
		checkintermission();
	if (interm && seconds > interm) {
		interm = 0;
		loopv(clients) if (clients[i].type != ST_EMPTY)
		{
			send2(true, i, SV_MAPRELOAD,
			    0); // ask a client to trigger map reload
			mapreload = true;
			break;

		}
	};

	resetserverifempty();

	if (!isdedicated)
		return; // below is network only

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
		switch (event.type) {
		case ENET_EVENT_TYPE_CONNECT: {
			client &c = addclient();
			c.type = ST_TCPIP;
			c.peer = event.peer;
			c.peer->data = (void *)(&c - &clients[0]);
			char hn[1024];
			strcpy_s(
			    c.hostname, (enet_address_get_host(&c.peer->address,
			                     hn, sizeof(hn)) == 0)
			                    ? hn
			                    : "localhost");
			printf("client connected (%s)\n", c.hostname);
			send_welcome(lastconnect = &c - &clients[0]);
			break;
		}
		case ENET_EVENT_TYPE_RECEIVE:
			brec += event.packet->dataLength;
			process(event.packet, (intptr_t)event.peer->data);







|
|
|
|
|







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
		switch (event.type) {
		case ENET_EVENT_TYPE_CONNECT: {
			client &c = addclient();
			c.type = ST_TCPIP;
			c.peer = event.peer;
			c.peer->data = (void *)(&c - &clients[0]);
			char hn[1024];
			strcpy_s(c.hostname,
			    (enet_address_get_host(
			         &c.peer->address, hn, sizeof(hn)) == 0)
			        ? hn
			        : "localhost");
			printf("client connected (%s)\n", c.hostname);
			send_welcome(lastconnect = &c - &clients[0]);
			break;
		}
		case ENET_EVENT_TYPE_RECEIVE:
			brec += event.packet->dataLength;
			process(event.packet, (intptr_t)event.peer->data);
489
490
491
492
493
494
495
496

497
498
499
500
501
502
503

504
505
506
507
508
509
510

511
512
513
514
515
516
517
518
519

520
521
522
523
524
525
526
		if (numplayers > maxclients) {
			disconnect_client(lastconnect, "maxclients reached");
		};
	};
#ifndef _WIN32
	fflush(stdout);
#endif
};


void
cleanupserver()
{
	if (serverhost)
		enet_host_destroy(serverhost);
};


void
localdisconnect()
{
	loopv(clients) if (clients[i].type == ST_LOCAL) clients[i].type =
	    ST_EMPTY;
};


void
localconnect()
{
	client &c = addclient();
	c.type = ST_LOCAL;
	strcpy_s(c.hostname, "local");
	send_welcome(&c - &clients[0]);
};


void
initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
    OFString *master, OFString *passwd, int maxcl)
{
	serverpassword = passwd;
	maxclients = maxcl;







<
>






<
>






<
>








<
>







489
490
491
492
493
494
495

496
497
498
499
500
501
502

503
504
505
506
507
508
509

510
511
512
513
514
515
516
517
518

519
520
521
522
523
524
525
526
		if (numplayers > maxclients) {
			disconnect_client(lastconnect, "maxclients reached");
		};
	};
#ifndef _WIN32
	fflush(stdout);
#endif

}

void
cleanupserver()
{
	if (serverhost)
		enet_host_destroy(serverhost);

}

void
localdisconnect()
{
	loopv(clients) if (clients[i].type == ST_LOCAL) clients[i].type =
	    ST_EMPTY;

}

void
localconnect()
{
	client &c = addclient();
	c.type = ST_LOCAL;
	strcpy_s(c.hostname, "local");
	send_welcome(&c - &clients[0]);

}

void
initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
    OFString *master, OFString *passwd, int maxcl)
{
	serverpassword = passwd;
	maxclients = maxcl;
550
551
552
553
554
555
556
557

		printf("dedicated server started, waiting for "
		       "clients...\nCtrl-C to exit\n\n");
		atexit(cleanupserver);
		atexit(enet_deinitialize);
		for (;;)
			serverslice(/*enet_time_get_sec()*/ time(NULL), 5);
	};
};








<
>
550
551
552
553
554
555
556

557
		printf("dedicated server started, waiting for "
		       "clients...\nCtrl-C to exit\n\n");
		atexit(cleanupserver);
		atexit(enet_deinitialize);
		for (;;)
			serverslice(/*enet_time_get_sec()*/ time(NULL), 5);
	};

}