[Tux4kids-commits] r1152 - tuxmath/branches/lan/server

David Bruce dbruce-guest at alioth.debian.org
Tue Jul 7 00:40:23 UTC 2009


Author: dbruce-guest
Date: 2009-07-07 00:40:23 +0000 (Tue, 07 Jul 2009)
New Revision: 1152

Modified:
   tuxmath/branches/lan/server/mathcards.c
   tuxmath/branches/lan/server/mathcards.h
   tuxmath/branches/lan/server/server.c
   tuxmath/branches/lan/server/server.h
   tuxmath/branches/lan/server/testclient.c
   tuxmath/branches/lan/server/transtruct.h
Log:
further implementation of server and command-line client



Modified: tuxmath/branches/lan/server/mathcards.c
===================================================================
--- tuxmath/branches/lan/server/mathcards.c	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/mathcards.c	2009-07-07 00:40:23 UTC (rev 1152)
@@ -185,6 +185,7 @@
 MC_Options* math_opts = 0;
 MC_MathQuestion* question_list = 0;
 MC_MathQuestion* wrong_quests = 0;
+MC_MathQuestion* active_quests = 0;
 MC_MathQuestion* next_wrong_quest = 0;
 int initialized = 0;
 int quest_list_length = 0;
@@ -352,7 +353,9 @@
   question_list = NULL;
   delete_list(wrong_quests);
   wrong_quests = NULL;
-
+  delete_list(active_quests);
+  active_quests = NULL;
+  
   /* clear the time list */
   if (time_per_question_list != NULL) {
     free(time_per_question_list);
@@ -442,6 +445,8 @@
     question_list = wrong_quests;
     wrong_quests = 0;
     next_wrong_quest = 0;
+    delete_list(active_quests);
+    active_quests = 0;
    /* initialize counters for new game: */
     quest_list_length = list_length(question_list);
     unanswered = starting_length = quest_list_length;
@@ -503,11 +508,12 @@
   /* 'draw' - copy over the first question */
   copy_card(&question_list->card, fc);
  
-  /* 'discard' - take first question node out of list and free it */
+  /* take first question node out of list and move it into active_quests list: */
   question_list = remove_node(question_list, question_list);
-  free_node(ptr);
+//  free_node(ptr);
   quest_list_length--;
   questions_pending++;
+  append_node(active_quests, ptr);
 
   #ifdef MC_DEBUG
   printf("\nnext question is:");
@@ -519,6 +525,8 @@
   return 1;
 }
 
+
+
 /*  MC_AnsweredCorrectly() is how the user interface      */
 /*  tells MathCards that the question has been answered   */
 /*  correctly. Returns 1 if no errors.                    */
@@ -541,6 +549,7 @@
   print_card(*fc);
   #endif
 
+  //FIXME we need to take the question out of the active_quests list
   answered_correctly++;
   questions_pending--;
 
@@ -575,6 +584,11 @@
   return 1;
 }
 
+int MC_AnsweredCorrectly_id(int id)
+{
+  return 1;
+}
+
 /*  MC_NotAnsweredCorrectly() is how the user interface    */
 /*  tells MathCards that the player failed to answer the  */
 /*  question correctly. Returns 1 if no errors.           */

Modified: tuxmath/branches/lan/server/mathcards.h
===================================================================
--- tuxmath/branches/lan/server/mathcards.h	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/mathcards.h	2009-07-07 00:40:23 UTC (rev 1152)
@@ -205,6 +205,7 @@
 /*  tells MathCards that the question has been answered   */
 /*  correctly. Returns 1 if no errors.                    */
 int MC_AnsweredCorrectly(MC_FlashCard* q);
+int MC_AnsweredCorrectly_id(int id);
 
 /*  MC_NotAnsweredCorrectly() is how the user interface    */
 /*  tells MathCards that the question has not been        */

Modified: tuxmath/branches/lan/server/server.c
===================================================================
--- tuxmath/branches/lan/server/server.c	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/server.c	2009-07-07 00:40:23 UTC (rev 1152)
@@ -49,9 +49,10 @@
 void start_game(int i);
 int SendQuestion(MC_FlashCard flash, TCPsocket client_sock);
 int SendMessage(int message, int ques_id,char *name, TCPsocket client_sock);
+int player_msg(int i, char* msg);
+void broadcast_msg(char* msg);
+void throttle(int loop_msec);
 
-
-
 /* "Local globals" for server.c:   */
 TCPsocket server_sock = NULL; /* Socket descriptor for server            */
 IPaddress ip;
@@ -82,9 +83,9 @@
   /*    ------------- Main server loop:  ------------------   */
   while (!quit)
   {
-    frame++;
-    /* See if our existing clients are really still there. For */
-    /* performance reasons, we don't do this on every loop:    */
+//    frame++;
+//    /* See if our existing clients are really still there. For */
+//    /* performance reasons, we don't do this on every loop:    */
 //    if(frame%1000 == 0)
 //      test_connections();
 
@@ -92,6 +93,11 @@
     update_clients();
     /* Check for any pending messages from clients already connected: */
     check_messages();
+    /* Limit frame rate to keep from eating all CPU: */
+    /* NOTE almost certainly could make this longer wtihout noticably */
+    /* affecting performance, but even throttling to 1 msec/loop cuts */
+    /* CPU from 100% to ~2% on my desktop - DSB                       */
+    throttle(1);  //min loop time 1 msec
   }
    
   /*   -----  Free resources before exiting: -------    */
@@ -197,7 +203,6 @@
 //update_clients() sees if anyone is trying to connect, and connects if a slot
 //is open and the game is not in progress. The purpose is to make sure our
 //client set accurately reflects the current state.
-//FIXME we need to be able to test to see if the clients are really still connected
 void update_clients(void)
 {
   TCPsocket temp_sock = NULL;        /* Just used when client can't be accepted */
@@ -264,7 +269,13 @@
   {
     strncpy(client[slot].name, buffer, NAME_SIZE);
     printf(" JOINED  :::   %s\n", client[slot].name);
+    //Announcement for all clients:
+    snprintf(buffer, NET_BUF_LEN, 
+          "Player %s has connected to the server\n",
+           client[slot].name);             
+    broadcast_msg(buffer);
 
+
     /* Add client socket to set: */
     sockets_used = SDLNet_TCP_AddSocket(client_set, client[slot].sock);
     if(sockets_used == -1) //No way this should happen
@@ -329,7 +340,7 @@
   //NOTE Does this belong here? Seems to have more to do wth client connections.
   if(game_in_progress==1)
   {
-    for(i = 0; i <MAX_CLIENTS; i++)
+    for(i = 0; i < MAX_CLIENTS; i++)
     {
       if(client[i].sock != NULL)
       {
@@ -431,6 +442,7 @@
 #ifdef LAN_DEBUG  
   printf("Buffer received from client: %s\n", buffer);
 #endif
+
   sscanf (buffer,"%s %d\n",
                   command,
                   &id);
@@ -450,7 +462,10 @@
     game_msg_quit(i);
     return(1);
   }
-
+  else
+  {
+    printf("command %s not recognized\n", command);
+  }
   return(0);
 }
 
@@ -458,20 +473,18 @@
 void game_msg_correct_answer(int i,int id)
 {
   int n;
-  printf("question id %d was answered correctly by %s",id,client[i].name);             
- 
- /*Send score notification to all the clients except the one who answered it*/
- for(n = 0; n < MAX_CLIENTS && client[n].sock; n++)
-  {
-    if(n==i)      /*I dont think , we would like to send it to the client who answered it*/
-    continue;
-    if(!SendMessage(ANSWER_CORRECT,id,client[i].name,client[n].sock))
-    {
-      printf("Unable to score changes\n");
-    }
-  }
+  char buf[NET_BUF_LEN];
 
+  //Announcement for server and all clients:
+  snprintf(buf, NET_BUF_LEN, 
+          "question id %d was answered correctly by %s\n",
+          id, client[i].name);             
+  printf("%s", buf);
+  broadcast_msg(buf);
 
+  //Tell mathcards so lists get updated:
+  MC_AnsweredCorrectly_id(id);
+
   if (!MC_NextQuestion(&flash))
   { 
     /* no more questions available */
@@ -560,7 +573,7 @@
   remove_client(i);
 }
 
-
+//FIXME don't think we want to allow players to shut down the server
 void game_msg_quit(int i)
 {
   printf("Server has been shut down by %s\n",client[i].name); 
@@ -576,8 +589,8 @@
   int x,j;
   game_in_progress = 1;  //setting the game_in_progress flag to '1'
   snprintf(buf, NET_BUF_LEN,
-                "%s\n",
-                "Success");  //FIXME what did we succeed at? This is basically a sort of handshaking signal , although it is not much needed here , but since we have a blocking recv call in the client for the case of game_in_progress , so no client join , therefore it is in accordance with that SDL_NetRecv()
+                "Player %s added for next math game\n",
+                client[i].name);
 
   x = SDLNet_TCP_Send(client[i].sock, buf, sizeof(buf));
   client[i].game_ready = 1; // Means this player is ready to start game
@@ -751,117 +764,86 @@
 }
 
 
-//Commented-out copy of old check_messages() to keep ping work from 
-//being lost
 
-// int check_messages(void)
-// {
-//   int i = 0;
-//   int actives = 0;
-//   int msg_found = 0;
-//   char buffer[NET_BUF_LEN];
-// 
-//   /* Check the client socket set for activity: */
-//   actives = SDLNet_CheckSockets(client_set, 0);
-//   if(actives == -1)
-//   {
-//     printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
-//     //most of the time this is a system error, where perror might help you.
-//     perror("SDLNet_CheckSockets");
-//   }
-// 
-//   else if(actives) 
-//   {
-// #ifdef LAN_DEBUG
-//     printf("There are %d sockets with activity\n", actives);
-// #endif
-// 
-//     // check all sockets with SDLNet_SocketReady and handle the active ones.
-//     // NOTE we have to check all the slots in the set because
-//     // the set will become discontinuous if someone disconnects
-//     for(i = 0; i < MAX_CLIENTS; i++)
-//     {
-//       if((client[i].sock != NULL)
-//         && (SDLNet_SocketReady(client[i].sock))) 
-//       {
-// #ifdef LAN_DEBUG
-//         printf("client socket %d is ready\n", i);
-// #endif
-//         if (SDLNet_TCP_Recv(client[i].sock, buffer, NET_BUF_LEN) > 0)
-//         {
-// #ifdef LAN_DEBUG
-//           printf("buffer received from client %d is: %s\n", i, buffer);
-// #endif
-//           msg_found++;
-// 
-//           /* Here we pass the client number and the message buffer */
-//           /* to a suitable function for further action:                */
-//            if(game_in_progress==1)
-//            {
-//             if(handle_client_game_msg(i, buffer))
-//             return(1);
-//            }
-//            if(game_in_progress==0)
-//            handle_client_nongame_msg(i,buffer);
-// 
-//         }
-//       }
-//     }  // end of for() loop - all client sockets checked
-//     // Make sure all the active sockets reported by SDLNet_CheckSockets()
-//     // are accounted for:
-//     if(actives == 0)
-//     {
-//       printf("Warning: SDLNet_CheckSockets() reported %d active sockets,\n"
-//              "but only %d messages received.\n", actives, msg_found);
-//       /* We can investigate further - maybe ping all the sockets, etc. */
-//       for(i = 0; i < MAX_CLIENTS; i++)
-//       {
-//         ping_client(i);
-//       }
-//     
-//    
-//       /* Check the client socket set for activity: */
-//       actives = SDLNet_CheckSockets(client_set, 5000);
-//       if(actives == 0)
-//       {
-//         printf("No clients , All clients have disconnected...=(\n");
-//       }
-// 
-//       else if(actives == -1)
-//       {
-//         printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
-//         //most of the time this is a system error, where perror might help you.
-//         perror("SDLNet_CheckSockets");
-//       }
-// 
-//       else if(actives) 
-//       {
-// #ifdef LAN_DEBUG
-//        printf("There are %d sockets with activity\n", actives);
-// #endif
-// 
-//        // check all sockets with SDLNet_SocketReady and handle the active ones.
-//        // NOTE we have to check all the slots in the set because
-//        // the set will become discontinuous if someone disconnects
-//        for(i = 0; i < MAX_CLIENTS; i++)
-//        {
-//          if((client[i].sock != NULL)
-//             && (SDLNet_SocketReady(client[i].sock))) 
-//          {
-// #ifdef LAN_DEBUG
-//            printf("client socket %d is ready\n", i);
-// #endif
-//            if (SDLNet_TCP_Recv(client[i].sock, buffer, NET_BUF_LEN) > 0)
-//            {
-// #ifdef LAN_DEBUG
-//              printf("buffer received from client %d is: %s\n", i, buffer);
-// #endif
-//              if(strncmp(buffer,"PING_BACK",9))
-//              printf("%s is connected =) \n",client[i].name);       
-//            }
-//          }
-//        }
-//       }
-//     }
-//   }
-// }
+/* Sends a string to be displayed to player: */
+/* NOTE similar in concept to SendMessage(), but I think that */
+/* SendMessage() is too complicated -DSB                      */
+int player_msg(int i, char* msg)
+{
+  char buf[NET_BUF_LEN];
+
+  //Validate arguments;
+  if(i < 0 || i > MAX_CLIENTS)
+  {
+#ifdef LAN_DEBUG
+    printf("player_msg() - invalid index argument\n");
+#endif
+  return 0;
+  }
+  
+  if(!client[i].sock)
+  {
+#ifdef LAN_DEBUG
+    printf("player_msg() - client socket is NULL\n");
+#endif
+  return 0;
+  }
+  
+  if(!msg)
+  {
+#ifdef LAN_DEBUG
+    printf("player_msg() - msg argument is NULL\n");
+#endif
+  return 0;
+  }
+
+  //transmit:
+  snprintf(buf, NET_BUF_LEN, "%s\t%s\n", "PLAYER_MSG", msg);
+  if(SDLNet_TCP_Send(client[i].sock, buf, NET_BUF_LEN) < NET_BUF_LEN)
+  {
+    printf("The client %s is disconnected\n", client[i].name);
+    remove_client(i);
+    return 0;
+  }
+  //Success:
+  return 1;
+}
+
+
+void broadcast_msg(char* msg)
+{
+  int i = 0;
+  if (!msg)
+    return;
+  for(i = 0; i < MAX_CLIENTS; i++)
+    player_msg(i, msg);   
+}
+
+
+
+void throttle(int loop_msec)
+{
+  static Uint32 now_t, last_t; //These will be zero first time through
+  int wait_t;
+
+  //Target loop time must be between 0 and 100 msec:
+  if(loop_msec < 0)
+    loop_msec = 0;
+  if(loop_msec > 100)
+    loop_msec = 100;
+
+  if (now_t == 0)  //For sane behavior first time through:
+    last_t = SDL_GetTicks();
+  else
+    last_t = now_t;
+  now_t = SDL_GetTicks();
+  wait_t = (last_t + loop_msec) - now_t;
+
+  //Avoid problem if we somehow wrap past uint32 size
+  if(wait_t < 0)
+    wait_t = 0;
+  if(wait_t > loop_msec)
+    wait_t = loop_msec;
+
+  SDL_Delay(wait_t);
+}

Modified: tuxmath/branches/lan/server/server.h
===================================================================
--- tuxmath/branches/lan/server/server.h	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/server.h	2009-07-07 00:40:23 UTC (rev 1152)
@@ -11,12 +11,13 @@
 
 */
 
+#ifndef SERVER_H
+#define SERVER_H
 
+
 #include "SDL_net.h"
 #define NAME_SIZE 50
 
-#ifndef SERVER_H
-#define SERVER_H
 typedef struct client_type {
   int game_ready;                 //game_ready = 1 , if client has said OK to start, and 0 otherwise
   char name[NAME_SIZE];

Modified: tuxmath/branches/lan/server/testclient.c
===================================================================
--- tuxmath/branches/lan/server/testclient.c	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/testclient.c	2009-07-07 00:40:23 UTC (rev 1152)
@@ -28,109 +28,57 @@
 #include "mathcards.h"
 #include "testclient.h"
 
-
+/* Local (to testclient.c) "globals": */
 TCPsocket sd;           /* Server socket descriptor */
 SDLNet_SocketSet set;
-
+IPaddress ip;           /* Server address */
+int len = 0;
+int sockets_used = 0;
+int quit = 0;
 MC_FlashCard flash;    //current question
-int quit = 0;
 
+/* Local function prototypes: */
+int setup_client(int argc, char **argv);
+void cleanup_client(void);
 int Make_Flashcard(char *buf, MC_FlashCard* fc);
 int LAN_AnsweredCorrectly(MC_FlashCard* fc);
 int playgame(void);
 void server_pinged(void);
 
+int player_msg_recvd(char* buf);
+int read_stdin_nonblock(char* buf, size_t max_length);
+void throttle(int loop_msec);
 
+
+
 int main(int argc, char **argv)
 {
-  IPaddress ip;           /* Server address */
-  int len, sockets_used;
   char buf[NET_BUF_LEN];     // for network messages from server
   char buffer[NET_BUF_LEN];  // for command-line input
-  char *check1;
-  char name[NAME_SIZE];
 
 
-
-
-
-  /* Simple parameter checking */
-  if (argc < 3)
+  /* Connect to server, create socket set, get player nickname, etc: */
+  if(!setup_client(argc, argv))
   {
-    fprintf(stderr, "Usage: %s host port\n", argv[0]);
+    printf("setup_client() failed - exiting.\n");
     exit(EXIT_FAILURE);
   }
 
-  if (SDLNet_Init() < 0)
-  {
-    fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
-    exit(EXIT_FAILURE);
-  }
- 
-  /* Resolve the host we are connecting to */
-  if (SDLNet_ResolveHost(&ip, argv[1], atoi(argv[2])) < 0)
-  {
-    fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
-    exit(EXIT_FAILURE);
-  }
- 
-  /* Open a connection with the IP provided (listen on the host's port) */
-  if (!(sd = SDLNet_TCP_Open(&ip)))
-  {
-    fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
-    exit(EXIT_FAILURE);
-  }
 
-  /* We create a socket set so we can check for activity: */
-  set = SDLNet_AllocSocketSet(1);
-  if(!set) {
-    printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
-    exit(EXIT_FAILURE);
-  }
 
-  sockets_used = SDLNet_TCP_AddSocket(set, sd);
-  if(sockets_used == -1) {
-    printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
-    // perhaps you need to restart the set and make it bigger...
-  }
+  printf("Welcome to the Tux Math Test Client!\n");
 
-
-  /* Now we are connected. Take in nickname and send to server. */
-
-  /* first just take in the name */
-  printf("Enter your Name.\n");
-  check1=gets(name);
-  if(check1==NULL)
-  printf(" gets() failed...\n");
- 
-  snprintf(buffer, NET_BUF_LEN, 
-                       "%s\n",
-                       name);
- 
-  if (SDLNet_TCP_Send(sd, (void *)buffer, NET_BUF_LEN) < NET_BUF_LEN)
-  {
-   fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
-   exit(EXIT_FAILURE);
-  }
-
-#ifdef LAN_DEBUG
-  printf("Sent the name of the player %s\n",check1);
-#endif
-
-
-
   /* Send messages */
   quit = 0;
   do
   { 
     //Get user input from command line and send it to server: 
     /*now display the options*/
-    printf("Welcome to the Tux Math Test Client!\n");
     printf("Type:\n"
              "'game' to start math game;\n"
              "'exit' to end client leaving server running;\n"
              "'quit' to end both client and server\n>\n"); 
-    char *check;
+    char* check;
     check = fgets(buffer, NET_BUF_LEN, stdin);
 
     //Figure out if we are trying to quit:
@@ -147,7 +95,6 @@
     }
     else if (strncmp(buffer, "game",4) == 0)
     {
-      printf("Starting Tux, of the Math Command Line ;-)\n");
       playgame();
       printf("Math game finished.\n");
     }
@@ -158,6 +105,8 @@
              "'exit' to end client leaving server running;\n"
              "'quit' to end both client and server\n\n>\n");
     }
+    //Limit loop to once per 10 msec so we don't eat all CPU
+    throttle(10);
   }while(!quit);
  
   SDLNet_TCP_Close(sd);
@@ -170,7 +119,86 @@
 }
 
 
+/* Establish networking and identify player to server: */
+int setup_client(int argc, char **argv)
+{
+  char* check1 = NULL;
+  char name[NAME_SIZE];
+  char buffer[NET_BUF_LEN];  // for command-line input
 
+
+  /* Simple parameter checking */
+  if (argc < 2)
+  {
+    fprintf(stderr, "Usage: %s host\n", argv[0]);
+    return 0;
+  }
+
+  if (SDLNet_Init() < 0)
+  {
+    fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
+    return 0;
+  }
+ 
+  /* Resolve the host we are connecting to */
+  if (SDLNet_ResolveHost(&ip, argv[1], DEFAULT_PORT) < 0)
+  {
+    fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+    return 0;
+  }
+ 
+  /* Open a connection with the IP provided (listen on the host's port) */
+  if (!(sd = SDLNet_TCP_Open(&ip)))
+  {
+    fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  /* We create a socket set so we can check for activity: */
+  set = SDLNet_AllocSocketSet(1);
+  if(!set)
+  {
+    printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  sockets_used = SDLNet_TCP_AddSocket(set, sd);
+  if(sockets_used == -1)
+  {
+    printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
+    // perhaps you need to restart the set and make it bigger...
+    return 0;
+  }
+  /* Now we are connected. Take in nickname and send to server. */
+  printf("Please enter your name:\n>\n");
+  check1 = fgets(buffer, NAME_SIZE, stdin);
+  strncpy(name, check1, NAME_SIZE);
+  /* If no nickname received, use default: */
+  if(strlen(name) == 1)
+    strcpy(name, "Anonymous Coward");
+  
+  printf("name is %s, length %d\n", name, strlen(name));
+  printf("buffer is %s, length %d\n", buffer, strlen(buffer));
+
+  snprintf(buffer, NET_BUF_LEN, "%s", name);
+
+
+  if (SDLNet_TCP_Send(sd, (void*)buffer, NET_BUF_LEN) < NET_BUF_LEN)
+  {
+    fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+#ifdef LAN_DEBUG
+  printf("Sent the name of the player %s\n",check1);
+#endif
+
+  return 1;
+}
+
+
+
+
 int LAN_AnsweredCorrectly(MC_FlashCard* fc)
 {
   int len;
@@ -267,28 +295,27 @@
   char buf[NET_BUF_LEN];
   char buffer[NET_BUF_LEN];
   char ch;
-  char* term;
-  size_t bytes_read = 0;
 
   /* Set stdin to be non-blocking: */
+  /* FIXME we might need to turn this back to blocking when we leave playgame() */
   fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
 
-#ifdef LAN_DEBUG
-  printf("Entering playgame()\n");
-#endif
+  printf("\nStarting Tux, of the Math Command Line ;-)\n");
+  printf("Waiting for other players to be ready...\n\n");
 
+
  
-   snprintf(buffer, NET_BUF_LEN, 
+  snprintf(buffer, NET_BUF_LEN, 
                   "%s\n",
                   "START_GAME");
-   len = strlen(buffer) + 1;
-   if (SDLNet_TCP_Send(sd, (void *)buffer, NET_BUF_LEN) < NET_BUF_LEN)
-   {
-     fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
-     exit(EXIT_FAILURE);
-   }
- #ifdef LAN_DEBUG
-   printf("Sent the game notification %s\n",buffer);
+  len = strlen(buffer) + 1;
+  if (SDLNet_TCP_Send(sd, (void *)buffer, NET_BUF_LEN) < NET_BUF_LEN)
+  {
+    fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
+    exit(EXIT_FAILURE);
+  }
+#ifdef LAN_DEBUG
+  printf("Sent the game notification %s\n",buffer);
  #endif
  
 
@@ -361,9 +388,12 @@
             // Presumably we want to print the message to stdout
             printf("%s\n", buf);
           }
-
-          else if(strncmp(command,"PING", strlen("PING")) == 0)
+          else if(strncmp(command,"PLAYER_MSG", strlen("PLAYER_MSG")) == 0)
           {
+            player_msg_recvd(buf);
+          }
+	  else if(strncmp(command,"PING", strlen("PING")) == 0)
+          {
             server_pinged();
           }
         }
@@ -375,57 +405,47 @@
 #endif
 
     //Now we check for any user responses
-//    while(have_question && !end)
-    { 
-      buf[0] = '\0';
-      bytes_read = fread (buf, 1, NET_BUF_LEN, stdin);
-      term = strchr(buf, '\n');
-      if (term)
-        *term = '\0';
-      
-#ifdef LAN_DEBUG
-//      printf("\nbytes_read is %d\n", bytes_read);
-//      printf("buf is %s\n", buf);
-#endif
-     
 
-      if(bytes_read == 0)
+    //This function returns 1 and updates buf with input from
+    //stdin if input is present.
+    //If no input, it returns 0 without blocking or waiting
+    if(read_stdin_nonblock(buf, NET_BUF_LEN))
+    {
+      if ((strncmp(buf, "quit", 4) == 0)
+        ||(strncmp(buf, "exit", 4) == 0)
+        ||(strncmp(buf, "q", 1) == 0))
       {
-//        printf("no input\n");
-//        SDL_Delay(2000);
+        quit = 1;  //So we exit loop in main()
+        end = 1;   //Exit our loop in playgame()
       }
+      else if(strncmp(buf,"PLAYER_MSG", strlen("PLAYER_MSG")) == 0)
+      {
+        player_msg_recvd(buf);
+      } 
       else
       {
-        if ((strncmp(buf, "quit", 4) == 0)
-          ||(strncmp(buf, "exit", 4) == 0)
-	  ||(strncmp(buf, "q", 1) == 0))
-        {
-          quit = 1;  //So we exit loop in main()
-          end = 1;   //Exit our loop in playgame()
+        /*NOTE atoi() will return zero for any string that is not
+        a valid int, not just '0' - should not be a big deal for
+        our test program - DSB */
+        ans = atoi(buf);
+        if(have_question && (ans == flash.answer))
+        {  
+          have_question = 0;
+          printf("%s is correct!\nRequesting next question...\n>\n", buf);
+
+          //Tell server we answered it right:
+          if(!LAN_AnsweredCorrectly(&flash))
+          {
+            printf("Unable to communicate the same to server\n");
+            exit(EXIT_FAILURE);
+          }
         }
-        else
-        {
-          /*NOTE atoi() will return zero for any string that is not
-          a valid int, not just '0' - should not be a big deal for
-          our test program - DSB */
-          ans = atoi(buf);
-          if(have_question && (ans == flash.answer))
-          {  
-            have_question = 0;
-            printf("%s is correct!\nRequesting next question...\n>\n", buf);
+        else  //we got input, but not the correct answer:
+          printf("Sorry, %s is incorrect. Try again!\n>\n", buf);
+      }  //input wasn't any of our keywords
+    } // Input was received 
 
-            //Tell server we answered it right:
-            if(!LAN_AnsweredCorrectly(&flash))
-            {
-              printf("Unable to communicate the same to server\n");
-              exit(EXIT_FAILURE);
-            }
-          }
-          else  //we got input, but not the correct answer:
-            printf("Sorry, %s is incorrect. Try again!\n>\n", buf);
-        }  //input wasn't any of our keywords
-      } // Input was received 
-    }  // End of while loop
+    throttle(10);  //so don't eat all CPU
   } //End of game loop 
 #ifdef LAN_DEBUG
   printf("Leaving playgame()\n");
@@ -433,3 +453,71 @@
 }
 
 
+//Goes past the title field in the tab-delimited buffer
+//and prints the rest to stdout:
+int player_msg_recvd(char* buf)
+{
+  char* p = strchr(buf, '\t');
+  if(p)
+  { 
+    p++;
+    printf("%s\n", p);
+    return 1;
+  }
+  else
+    return 0;
+}
+
+//Here we read up to max_length bytes from stdin into the buffer.
+//The first '\n' in the buffer, if present, is replaced with a
+//null terminator.
+//returns 0 if no data ready, 1 if at least one byte read.
+
+int read_stdin_nonblock(char* buf, size_t max_length)
+{
+  int bytes_read = 0;
+  char* term = NULL;
+  buf[0] = '\0';
+
+  bytes_read = fread (buf, 1, max_length, stdin);
+  term = strchr(buf, '\n');
+  if (term)
+    *term = '\0';
+     
+  if(bytes_read > 0)
+    bytes_read = 1;
+  else
+    bytes_read = 0;
+      
+  return bytes_read;
+}
+
+
+
+void throttle(int loop_msec)
+{
+  static Uint32 now_t, last_t; //These will be zero first time through
+  int wait_t;
+
+  //Target loop time must be between 0 and 100 msec:
+  if(loop_msec < 0)
+    loop_msec = 0;
+  if(loop_msec > 100)
+    loop_msec = 100;
+
+  if (now_t == 0)  //For sane behavior first time through:
+    last_t = SDL_GetTicks();
+  else
+    last_t = now_t;
+  now_t = SDL_GetTicks();
+  wait_t = (last_t + loop_msec) - now_t;
+
+  //Avoid problem if we somehow wrap past uint32 size
+  if(wait_t < 0)
+    wait_t = 0;
+  if(wait_t > loop_msec)
+    wait_t = loop_msec;
+
+  SDL_Delay(wait_t);
+}
+

Modified: tuxmath/branches/lan/server/transtruct.h
===================================================================
--- tuxmath/branches/lan/server/transtruct.h	2009-07-06 22:03:24 UTC (rev 1151)
+++ tuxmath/branches/lan/server/transtruct.h	2009-07-07 00:40:23 UTC (rev 1152)
@@ -14,7 +14,7 @@
 #ifndef TRANSTRUCT_H
 #define TRANSTRUCT_H
 
-//#define LAN_DEBUG
+#define LAN_DEBUG
 #define NET_BUF_LEN 512
 #define DEFAULT_PORT 4779
 #define NAME_SIZE 50




More information about the Tux4kids-commits mailing list