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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "server.h"
|
||||
#include "net.h"
|
||||
#include "game.h"
|
||||
#include "asciiart.h"
|
||||
|
||||
#define MAX_MSG_LEN 50
|
||||
/*
|
||||
typedef enum { MSG_MOVE, MSG_ROTATE } message_type_t;
|
||||
typedef struct {
|
||||
int players[2];
|
||||
game_t game;
|
||||
} server_game_t;
|
||||
|
||||
server_game_t *server_games[MAX_GAMES];
|
||||
int server_games_sz;
|
||||
|
||||
typedef struct {
|
||||
message_type_t type;
|
||||
union {
|
||||
struct {
|
||||
int row, col;
|
||||
dir_t dir;
|
||||
} move;
|
||||
struct {
|
||||
int row, col;
|
||||
rot_t dir;
|
||||
} rotate;
|
||||
} args;
|
||||
} message_t;
|
||||
int connected;
|
||||
char name[10];
|
||||
int game;
|
||||
int requested_game, requested_game_with;
|
||||
} server_client_t;
|
||||
|
||||
server_client_t server_clients[MAX_CLIENTS];
|
||||
|
||||
typedef int cmdfunc_t(int client, char **args);
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *desc;
|
||||
int argc;
|
||||
cmdfunc_t *func;
|
||||
} server_cmd_t;
|
||||
|
||||
int server_do_command(int clientid, char *cmd);
|
||||
|
||||
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;
|
||||
for (i = 0; i < MAX_MSG_LEN+1; i++) {
|
||||
c = net_getc(side);
|
||||
printf("input '%c'\n", c);
|
||||
if (c == '\n')
|
||||
break;
|
||||
buf[i] = c;
|
||||
}
|
||||
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;
|
||||
assert(id >= 0 && id < MAX_GAMES && server_games[id] != NULL);
|
||||
free(server_games[id]);
|
||||
server_games[id] = NULL;
|
||||
for (i = id+1; i < server_games_sz; i++)
|
||||
server_games[i-1] = server_games[i];
|
||||
server_games_sz--;
|
||||
}
|
||||
|
||||
int
|
||||
execute_message(game_t *game, message_t msg, int side)
|
||||
server_get_game_request(int client)
|
||||
{
|
||||
switch (msg.type) {
|
||||
case MSG_MOVE:
|
||||
return move(game, side,
|
||||
msg.args.move.row, msg.args.move.col,
|
||||
msg.args.move.dir, 0);
|
||||
case MSG_ROTATE:
|
||||
return rotate(game, side,
|
||||
msg.args.rotate.row, msg.args.rotate.col,
|
||||
msg.args.rotate.dir);
|
||||
default:
|
||||
net_side_printf(side, "unknown command type %d\n", msg.type);
|
||||
return E_UNKNOWN_COMMAND;
|
||||
int i;
|
||||
server_client_t *c = server_clients;
|
||||
for (i = 0; i < MAX_CLIENTS; i++) {
|
||||
if (c[i].connected &&
|
||||
c[i].requested_game &&
|
||||
(c[i].requested_game_with == client ||
|
||||
c[i].requested_game_with == -1))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
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
|
||||
terminal_game(void)
|
||||
@ -111,7 +125,7 @@ terminal_game(void)
|
||||
printf("%s", aabuf);
|
||||
|
||||
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);
|
||||
if (parse_move(linebuf, &move) != HUGE_SUCCESS) {
|
||||
printf("not a valid move description: '%s'\n", linebuf);
|
||||
@ -122,6 +136,9 @@ terminal_game(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
asciiart_small_draw_board(aabuf, &game);
|
||||
printf("%s", aabuf);
|
||||
|
||||
if (game.last_move.type == M_ROTATE) {
|
||||
printf("move: %c%c rotated %s\n",
|
||||
game.last_move.y+'A',
|
||||
@ -146,9 +163,6 @@ terminal_game(void)
|
||||
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
|
||||
}
|
||||
|
||||
asciiart_small_draw_board(aabuf, &game);
|
||||
printf("%s", aabuf);
|
||||
|
||||
switch (game.winner) {
|
||||
case SILVER:
|
||||
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
|
||||
parse_line(int clientid, char *line) {
|
||||
move_t move;
|
||||
if (parse_move(line, &move) != HUGE_SUCCESS) {
|
||||
net_client_printf(clientid, "not a valid move description: '%s'\n", line);
|
||||
server_do_move(int clientid, move_t move)
|
||||
{
|
||||
int gameid = server_clients[clientid].game;
|
||||
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;
|
||||
}
|
||||
if (perform_move(&game, clientid, move) != HUGE_SUCCESS) {
|
||||
default:
|
||||
net_client_printf(clientid, "invalid move\n");
|
||||
return;
|
||||
}
|
||||
|
||||
server_report_game_state(gameid);
|
||||
|
||||
if (game.last_move.type == M_ROTATE) {
|
||||
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) {
|
||||
switch (g->game.winner) {
|
||||
case SILVER:
|
||||
net_all_printf("SILVER WINS!\n");
|
||||
exit(0);
|
||||
server_delete_game(gameid);
|
||||
break;
|
||||
case RED:
|
||||
net_all_printf("RED WINS!\n");
|
||||
exit(0);
|
||||
server_delete_game(server_clients[clientid].game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parse_line(int clientid, char *line)
|
||||
{
|
||||
server_do_command(clientid, line);
|
||||
}
|
||||
|
||||
int player[2]={0, 0};
|
||||
|
||||
void
|
||||
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);
|
||||
player[clientid]=1;
|
||||
if (player[0] && player[1]) {
|
||||
@ -229,9 +288,122 @@ server_client_connect(int clientid) {
|
||||
asciiart_small_draw_board(aabuf, &game);
|
||||
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
|
||||
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 parse_line(int clientid, char *line);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user