Project by Aaron Visser, Andrew Juang, and Dylan Hu | Systems Period 4
TypeRacer is a multiplayer typing test racing game. You have to type a text as fast as you can to try and beat others who are typing the same text.
- ncurses
- On debian:
sudo apt install libncurses5-dev libncursesw5-dev
- On other systems google: "install ncurses (platform)" and follow instructions that look somewhat trustworthy
- On debian:
- Your compiler (gcc) must support C11 or higher
- Clone the Repository
git clone https://github.com/Andrew1J/TypeRacer.git
- Change Directories
cd TypeRacer
- Compile using make
make
- Run Server then run client
make server
and make client
in separate windows
- Press escape if you want to escape the client and ctrl-c if you want to stop the server
- You will have to rerun the server if you want a new lobby
Somewhat Notable Bugs and/or Problems (SOME OF these bugs may be resolved but we are leaving these here for now)
- random double free() errors in server may occur which causes client to crash
- Restart the server and user ctrl-c to exit the client if this occurs
- Calculation of WPM may not match other typing tests, as we're not exactly sure what values to use to calculate WPM from errors and number of typed characters
- client doesn't refresh until keyboard input, but you wouldn't really play the game by not typing
- floating point errors might occur
- Since network communication via TCP in C is a bit funky, we need a way to make sure that the data that we're sending over the network is completely transmitted and readable on the other side of the connection. We are sending more than just plain text over the network, so we need to be able to reliably tell the difference between many different types of messages.
- Each packet starts with
-=-=-=-=-=-
and ends with-+-+-+-+-+-
. The first byte after the beginning is the type of the packet. The rest of the packet is data. We will implement functions for every type of packet to send/recieve over a socket to be used in both the client and server. For packingint
s and others into portable formats, we will probably use the htons family of functions. Packets will be represented using structs to make our lives easier as we can pass them around easily.
- On connection username packet
This packet is the first packet sent from connecting clients to the server. It contains the username that the client has chosen. The first two (2) bytes contain the length of the username (unsigned int
). The rest contains the username. - New player joined packet
This packet is sent to already connected clients when new clients join the server. It contains the username of the client that has joined. For new clients, if there are already joined clients, the server will just send a bunch of these to the new client. - Typing text packet
This packet contains the text that the clients will type. The first two (2) bytes contain the length of the text (unsigned int
). The rest of the packet is the text. - Race countdown start packet
This packet signifies the start of a countdown until which the race will start. It contains the number of seconds until race start. - Race start packet
This packet signifies the start of the race (in case clients are delayed somehow). It contains no data. - Progress packet
This packet contains the username, percentage progress, and current WPM of the transmitting client. The first two (2) bytes contain the length of the username. Next is the username, and afterwards is two (2) bytes of the percentage progress, and finally two (2) bytes of the current WPM. All types areunsigned int
s.
- After startup, the server will bind to a port and being to listen for incoming connections.
- The server will generate the text to be out of an array of pointers to possible text string to be typed by all players. It will send this to all clients. (how?)
- While the race is ongoing, the server will
poll()
all of the client's sockets. This uses an array ofstruct pollfd
. If anything happens, the server will just go through all of the sockets and relay the message along.
The client is responsible for connecting to the server, recieving the text to type, displaying text and other players' progress on the screen, recieving input, and sending progress messages to the server. Keeping track of other players can be done with a linked list of structs, or just a regular array.
- On execution the client will prompt the user for an IP address or hostname to connect to as well as a username for the player. The client will then connect to the server specified using a socket, then it will send a message packet to the server containing the username selected. On connection to the server, the client will recieve a message packet from the server containing the text to type and the usernames of the other players, if applicable. The client will display the text on the screen while the server waits for others to connect. As others connect to the server, the client will recieve notification of these other clients and show their username/progress on the screen (which will be 0% as the game hasn't started yet).
- When the server sends a race start message packet, the client will display a countdown timer until the race starts. When the client recieves the race start message, it will move to the main race loop.
-
During the race, the client will have to be able to respond to keyboard input as well as incoming messages relayed by the server. ncurses provides a function to get the next character
getch()
, which can be set to a non-blocking buffered mode. The socket used to connect to the server will also be set to non-blocking mode. -
During the game loop, the client will continuously check for keyboard input using
getch()
, and if recieved process the input and redraw the screen. It will then callrecv()
and if any data is recieved, process and redraw the screen. A sleep of a small amount will be used in order to not absolutely eat up all the CPU cycles. -
To write text on the screen, ncurses provides a bunch of print functions, which can be used to print text into the terminal in arbitrary positions. ncurses also provides
attron()
andattroff()
to change the styling of the text.
- Whenever a character is typed, the client will increment a total character counter. If the character typed is incorrect, a incorrect character counter will be incremented. WPM is basically something like:
- After every word (every time the user passes a white space in the original text), the client will send the most recent progress and WPM in a packet to the server.
- Proposal (1/12)
- Complete protocol implementation (1/16)
- Client / Server initial connection (1/18)
- Set up UI using ncurses (1/18)
- Finish game loop portion (1/22)
- Set up single room, multiple users (1/22)
- Better Menus / GUI / Text Selection (Whatever remaining time we have)