more than two clients at the same time
This commit is contained in:
parent
9a73ba8e77
commit
eed9669db9
410
src/server.c
410
src/server.c
@ -4,98 +4,112 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "asciiart.h"
|
#include "asciiart.h"
|
||||||
|
|
||||||
#define MAX_MSG_LEN 50
|
typedef struct {
|
||||||
/*
|
int players[2];
|
||||||
typedef enum { MSG_MOVE, MSG_ROTATE } message_type_t;
|
game_t game;
|
||||||
|
} server_game_t;
|
||||||
|
|
||||||
|
server_game_t *server_games[MAX_GAMES];
|
||||||
|
int server_games_sz;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
message_type_t type;
|
int connected;
|
||||||
union {
|
char name[10];
|
||||||
struct {
|
int game;
|
||||||
int row, col;
|
int requested_game, requested_game_with;
|
||||||
dir_t dir;
|
} server_client_t;
|
||||||
} move;
|
|
||||||
struct {
|
server_client_t server_clients[MAX_CLIENTS];
|
||||||
int row, col;
|
|
||||||
rot_t dir;
|
typedef int cmdfunc_t(int client, char **args);
|
||||||
} rotate;
|
typedef struct {
|
||||||
} args;
|
char *name;
|
||||||
} message_t;
|
char *desc;
|
||||||
|
int argc;
|
||||||
|
cmdfunc_t *func;
|
||||||
|
} server_cmd_t;
|
||||||
|
|
||||||
|
int server_do_command(int clientid, char *cmd);
|
||||||
|
|
||||||
int
|
int
|
||||||
read_message(int side, message_t *m)
|
server_new_game(int silver, int red)
|
||||||
|
{
|
||||||
|
if (server_games_sz == MAX_GAMES)
|
||||||
|
return -1;
|
||||||
|
int game_id = server_games_sz++;
|
||||||
|
server_game_t *g = malloc(sizeof(server_game_t));
|
||||||
|
|
||||||
|
g->players[SILVER] = silver;
|
||||||
|
g->players[RED] = red;
|
||||||
|
server_clients[silver].game = game_id;
|
||||||
|
server_clients[red].game = game_id;
|
||||||
|
server_clients[silver].requested_game = 0;
|
||||||
|
server_clients[red].requested_game = 0;
|
||||||
|
|
||||||
|
init_game(&g->game);
|
||||||
|
setup_board(&g->game, classic_setup);
|
||||||
|
server_games[game_id] = g;
|
||||||
|
return game_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
server_delete_game(int id)
|
||||||
{
|
{
|
||||||
char buf[MAX_MSG_LEN+1];
|
|
||||||
char c;
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_MSG_LEN+1; i++) {
|
assert(id >= 0 && id < MAX_GAMES && server_games[id] != NULL);
|
||||||
c = net_getc(side);
|
free(server_games[id]);
|
||||||
printf("input '%c'\n", c);
|
server_games[id] = NULL;
|
||||||
if (c == '\n')
|
for (i = id+1; i < server_games_sz; i++)
|
||||||
break;
|
server_games[i-1] = server_games[i];
|
||||||
buf[i] = c;
|
server_games_sz--;
|
||||||
}
|
|
||||||
buf[i] = '\0';
|
|
||||||
while (c != '\n') c = net_getc(side);
|
|
||||||
|
|
||||||
switch (buf[0]) {
|
|
||||||
case 'M': m->type = MSG_MOVE; break;
|
|
||||||
case 'R': m->type = MSG_ROTATE; break;
|
|
||||||
default: return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m->type == MSG_MOVE) {
|
|
||||||
m->args.move.row = buf[2]-'A';
|
|
||||||
m->args.move.col = buf[3]-'0';
|
|
||||||
switch (buf[5]) {
|
|
||||||
case 'N':
|
|
||||||
m->args.move.dir = (buf[6]=='W' ? D_NW : (buf[6]=='E' ? D_NE : D_N));
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
m->args.move.dir = (buf[6]=='W' ? D_SW : (buf[6]=='E' ? D_SE : D_S));
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
m->args.move.dir = D_E;
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
m->args.move.dir = D_W;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_all_printf("msg: MOVE (%d,%d) %d\n", m->args.move.row, m->args.move.col,
|
|
||||||
m->args.move.dir);
|
|
||||||
} else if (m->type == MSG_ROTATE) {
|
|
||||||
m->args.rotate.row = buf[2]-'A';
|
|
||||||
m->args.rotate.col = buf[3]-'0';
|
|
||||||
m->args.rotate.dir = (buf[5]=='L' ? R_CCW : R_CW);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HUGE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
execute_message(game_t *game, message_t msg, int side)
|
server_get_game_request(int client)
|
||||||
{
|
{
|
||||||
switch (msg.type) {
|
int i;
|
||||||
case MSG_MOVE:
|
server_client_t *c = server_clients;
|
||||||
return move(game, side,
|
for (i = 0; i < MAX_CLIENTS; i++) {
|
||||||
msg.args.move.row, msg.args.move.col,
|
if (c[i].connected &&
|
||||||
msg.args.move.dir, 0);
|
c[i].requested_game &&
|
||||||
case MSG_ROTATE:
|
(c[i].requested_game_with == client ||
|
||||||
return rotate(game, side,
|
c[i].requested_game_with == -1))
|
||||||
msg.args.rotate.row, msg.args.rotate.col,
|
return i;
|
||||||
msg.args.rotate.dir);
|
}
|
||||||
default:
|
return -1;
|
||||||
net_side_printf(side, "unknown command type %d\n", msg.type);
|
}
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
|
int
|
||||||
|
server_request_game(int client, int opponent)
|
||||||
|
{
|
||||||
|
int match = 0;
|
||||||
|
if (server_clients[client].requested_game)
|
||||||
|
return -1;
|
||||||
|
if (opponent == -1) {
|
||||||
|
opponent = server_get_game_request(client);
|
||||||
|
if (opponent != -1) match = 1;
|
||||||
|
} else {
|
||||||
|
match =
|
||||||
|
server_clients[opponent].requested_game &&
|
||||||
|
(server_clients[opponent].requested_game_with == client ||
|
||||||
|
server_clients[opponent].requested_game_with == -1);
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
server_clients[opponent].requested_game = 0;
|
||||||
|
return server_new_game(client, opponent);
|
||||||
|
} else {
|
||||||
|
server_clients[client].requested_game = 1;
|
||||||
|
server_clients[client].requested_game_with = opponent;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
void
|
||||||
terminal_game(void)
|
terminal_game(void)
|
||||||
@ -111,7 +125,7 @@ terminal_game(void)
|
|||||||
printf("%s", aabuf);
|
printf("%s", aabuf);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
printf("%s's move\n", sideinfo[game_turn(&game)].name);
|
printf("move %d, %s\n", game.move, sideinfo[game_turn(&game)].name);
|
||||||
fgets(linebuf, 10, stdin);
|
fgets(linebuf, 10, stdin);
|
||||||
if (parse_move(linebuf, &move) != HUGE_SUCCESS) {
|
if (parse_move(linebuf, &move) != HUGE_SUCCESS) {
|
||||||
printf("not a valid move description: '%s'\n", linebuf);
|
printf("not a valid move description: '%s'\n", linebuf);
|
||||||
@ -122,6 +136,9 @@ terminal_game(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asciiart_small_draw_board(aabuf, &game);
|
||||||
|
printf("%s", aabuf);
|
||||||
|
|
||||||
if (game.last_move.type == M_ROTATE) {
|
if (game.last_move.type == M_ROTATE) {
|
||||||
printf("move: %c%c rotated %s\n",
|
printf("move: %c%c rotated %s\n",
|
||||||
game.last_move.y+'A',
|
game.last_move.y+'A',
|
||||||
@ -146,9 +163,6 @@ terminal_game(void)
|
|||||||
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
|
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
|
||||||
}
|
}
|
||||||
|
|
||||||
asciiart_small_draw_board(aabuf, &game);
|
|
||||||
printf("%s", aabuf);
|
|
||||||
|
|
||||||
switch (game.winner) {
|
switch (game.winner) {
|
||||||
case SILVER:
|
case SILVER:
|
||||||
printf("SILVER WINS!\n");
|
printf("SILVER WINS!\n");
|
||||||
@ -162,64 +176,109 @@ terminal_game(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
game_t game;
|
void
|
||||||
|
server_report_game_state(int gameid)
|
||||||
|
{
|
||||||
|
server_game_t *g = server_games[gameid];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
int c = g->players[i];
|
||||||
|
|
||||||
|
if (g->game.last_move.type == M_ROTATE) {
|
||||||
|
net_client_printf(c, "move: %c%c rotated %s\n",
|
||||||
|
g->game.last_move.y+'A',
|
||||||
|
g->game.last_move.x+'0',
|
||||||
|
g->game.last_move.dir==R_CW ? "R" : "L");
|
||||||
|
} else {
|
||||||
|
int nx, ny;
|
||||||
|
move_dest(g->game.last_move, &nx, &ny);
|
||||||
|
net_client_printf(c, "move: %c%c moved to %c%c\n",
|
||||||
|
g->game.last_move.y+'A',
|
||||||
|
g->game.last_move.x+'0',
|
||||||
|
ny+'A', nx+'0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->game.last_hit.piece != NONE) {
|
||||||
|
net_client_printf(c, "laser hits %s %s at %c%c\n",
|
||||||
|
sideinfo[g->game.last_hit.side].name,
|
||||||
|
pieceinfo[g->game.last_hit.piece].name,
|
||||||
|
g->game.laser_pos[1]+'A', g->game.laser_pos[0]+'0');
|
||||||
|
} else {
|
||||||
|
net_client_printf(c, "laser hits wall at %c%c\n",
|
||||||
|
g->game.laser_pos[1]+'A', g->game.laser_pos[0]+'0');
|
||||||
|
}
|
||||||
|
|
||||||
|
char aabuf[ASCIIART_SMALL_BUFSZ];
|
||||||
|
asciiart_small_draw_board(aabuf, &g->game);
|
||||||
|
net_client_printf(c, "%s", aabuf);
|
||||||
|
|
||||||
|
switch (g->game.winner) {
|
||||||
|
case SILVER:
|
||||||
|
net_client_printf(c, "SILVER WINS!\n");
|
||||||
|
break;
|
||||||
|
case RED:
|
||||||
|
net_client_printf(c, "RED WINS!\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (g->players[game_turn(&g->game)]==c)
|
||||||
|
net_client_printf(c, "your turn\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_line(int clientid, char *line) {
|
server_do_move(int clientid, move_t move)
|
||||||
move_t move;
|
{
|
||||||
if (parse_move(line, &move) != HUGE_SUCCESS) {
|
int gameid = server_clients[clientid].game;
|
||||||
net_client_printf(clientid, "not a valid move description: '%s'\n", line);
|
server_game_t *g = server_games[gameid];
|
||||||
|
int side;
|
||||||
|
|
||||||
|
side = (g->players[1]==clientid);
|
||||||
|
|
||||||
|
switch (perform_move(&g->game, side, move)) {
|
||||||
|
case HUGE_SUCCESS:
|
||||||
|
break;
|
||||||
|
case E_NOT_YOUR_TURN:
|
||||||
|
net_client_printf(clientid, "not your turn\n");
|
||||||
return;
|
return;
|
||||||
}
|
default:
|
||||||
if (perform_move(&game, clientid, move) != HUGE_SUCCESS) {
|
|
||||||
net_client_printf(clientid, "invalid move\n");
|
net_client_printf(clientid, "invalid move\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server_report_game_state(gameid);
|
||||||
|
|
||||||
if (game.last_move.type == M_ROTATE) {
|
switch (g->game.winner) {
|
||||||
net_all_printf("move: %c%c rotated %s\n",
|
|
||||||
game.last_move.y+'A',
|
|
||||||
game.last_move.x+'0',
|
|
||||||
game.last_move.dir==R_CW ? "R" : "L");
|
|
||||||
} else {
|
|
||||||
int nx, ny;
|
|
||||||
move_dest(game.last_move, &nx, &ny);
|
|
||||||
net_all_printf("move: %c%c moved to %c%c\n",
|
|
||||||
game.last_move.y+'A',
|
|
||||||
game.last_move.x+'0',
|
|
||||||
ny+'A', nx+'0');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game.last_hit.piece != NONE) {
|
|
||||||
net_all_printf("laser hits %s %s at %c%c\n",
|
|
||||||
sideinfo[game.last_hit.side].name,
|
|
||||||
pieceinfo[game.last_hit.piece].name,
|
|
||||||
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
|
|
||||||
} else {
|
|
||||||
net_all_printf("laser hits wall at %c%c\n",
|
|
||||||
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
|
|
||||||
}
|
|
||||||
|
|
||||||
char aabuf[ASCIIART_SMALL_BUFSZ];
|
|
||||||
asciiart_small_draw_board(aabuf, &game);
|
|
||||||
net_all_printf("%s", aabuf);
|
|
||||||
|
|
||||||
switch (game.winner) {
|
|
||||||
case SILVER:
|
case SILVER:
|
||||||
net_all_printf("SILVER WINS!\n");
|
server_delete_game(gameid);
|
||||||
exit(0);
|
break;
|
||||||
case RED:
|
case RED:
|
||||||
net_all_printf("RED WINS!\n");
|
server_delete_game(server_clients[clientid].game);
|
||||||
exit(0);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_line(int clientid, char *line)
|
||||||
|
{
|
||||||
|
server_do_command(clientid, line);
|
||||||
|
}
|
||||||
|
|
||||||
int player[2]={0, 0};
|
int player[2]={0, 0};
|
||||||
|
|
||||||
void
|
void
|
||||||
server_client_connect(int clientid) {
|
server_client_connect(int clientid) {
|
||||||
|
server_client_t *c = &server_clients[clientid];
|
||||||
|
c->connected = 1;
|
||||||
|
sprintf(c->name, "client%03d", clientid);
|
||||||
|
c->game = -1;
|
||||||
|
c->requested_game = 0;
|
||||||
|
|
||||||
|
net_client_printf(clientid, "Welcome to the KHET server\n");
|
||||||
|
net_client_printf(clientid, "Say 'play' to play a game\n");
|
||||||
|
net_client_printf(clientid, "(you may have to wait for another player)\n");
|
||||||
|
|
||||||
|
/*
|
||||||
assert(clientid<2);
|
assert(clientid<2);
|
||||||
player[clientid]=1;
|
player[clientid]=1;
|
||||||
if (player[0] && player[1]) {
|
if (player[0] && player[1]) {
|
||||||
@ -229,9 +288,122 @@ server_client_connect(int clientid) {
|
|||||||
asciiart_small_draw_board(aabuf, &game);
|
asciiart_small_draw_board(aabuf, &game);
|
||||||
net_all_printf("%s", aabuf);
|
net_all_printf("%s", aabuf);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
server_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
server_games_sz = 0;
|
||||||
|
for (i = 0; i < MAX_CLIENTS; i++)
|
||||||
|
server_clients[i].connected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
server_cmd_play(int client, char **args)
|
||||||
|
{
|
||||||
|
int g = server_request_game(client, -1);
|
||||||
|
if (g == -1) {
|
||||||
|
net_client_printf(client, "requested game with anyone\n");
|
||||||
|
} else {
|
||||||
|
server_report_game_state(g);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
server_cmd_playwith(int client, char **args)
|
||||||
|
{
|
||||||
|
net_client_printf(client, "sorry, this is not implemented yet\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
server_cmd_nick(int client, char **args)
|
||||||
|
{
|
||||||
|
net_client_printf(client, "sorry, this is not implemented yet\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
server_cmd_ls(int client, char **args)
|
||||||
|
{
|
||||||
|
net_client_printf(client, "sorry, this is not implemented yet\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_cmd_t server_commands[] = {
|
||||||
|
{ .name = "PLAY",
|
||||||
|
.desc = "play a game with anyone",
|
||||||
|
.argc = 0,
|
||||||
|
.func = server_cmd_play },
|
||||||
|
{ .name = "PLAYWITH",
|
||||||
|
.desc = "play a game with a named opponent",
|
||||||
|
.argc = 1,
|
||||||
|
.func = server_cmd_playwith },
|
||||||
|
{ .name = "NICK",
|
||||||
|
.desc = "set your nickname",
|
||||||
|
.argc = 1,
|
||||||
|
.func = server_cmd_nick },
|
||||||
|
{ .name = "LS",
|
||||||
|
.desc = "list stuff",
|
||||||
|
.argc = 1,
|
||||||
|
.func = server_cmd_ls } };
|
||||||
|
int server_commands_sz = 4;
|
||||||
|
|
||||||
|
int
|
||||||
|
server_do_command(int clientid, char *cmd)
|
||||||
|
{
|
||||||
|
char *cmd_copy = strdup(cmd);
|
||||||
|
server_cmd_t *cmd_type = NULL;
|
||||||
|
char *args[10];
|
||||||
|
int argc;
|
||||||
|
char *c;
|
||||||
|
move_t move;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < strlen(cmd_copy); i++) {
|
||||||
|
cmd_copy[i] = toupper(cmd_copy[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server_clients[clientid].game != -1 &&
|
||||||
|
parse_move(cmd_copy, &move) == HUGE_SUCCESS) {
|
||||||
|
server_do_move(clientid, move);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (argc = 0, c = cmd_copy; ; argc++) {
|
||||||
|
while (*c != ' ' && *c != '\n' && *c != '\0')
|
||||||
|
c++;
|
||||||
|
if (*c == ' ' || *c == '\n') *(c++) = '\0';
|
||||||
|
while (*c == ' ' || *c == '\n')
|
||||||
|
c++;
|
||||||
|
if (*c == '\n' || *c == '\0')
|
||||||
|
break;
|
||||||
|
args[argc] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < server_commands_sz; i++) {
|
||||||
|
if (strcmp(cmd_copy, server_commands[i].name)==0)
|
||||||
|
cmd_type = &server_commands[i];
|
||||||
|
}
|
||||||
|
if (cmd_type == NULL) {
|
||||||
|
net_client_printf(clientid, "unknown command %s\n", cmd_copy);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (argc != cmd_type->argc) {
|
||||||
|
net_client_printf(clientid,
|
||||||
|
"wrong number of arguments for %s (wanted %d, got %d)\n",
|
||||||
|
cmd_type->name, cmd_type->argc, argc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd_type->func(clientid, args);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
|
#ifndef KHET_SERVER_H
|
||||||
|
#define KHET_SERVER_H
|
||||||
|
|
||||||
|
#define MAX_GAMES 10
|
||||||
|
|
||||||
void server_client_connect(int clientid);
|
void server_client_connect(int clientid);
|
||||||
void parse_line(int clientid, char *line);
|
void parse_line(int clientid, char *line);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Reference in New Issue
Block a user