working on making game lobbies and joining them

This commit is contained in:
2026-01-31 18:42:43 -06:00
parent 89c9a7681b
commit 47987ca439
14 changed files with 227 additions and 280 deletions

View File

@@ -4,8 +4,8 @@ CC =gcc
CFLAGS =-g CFLAGS =-g
CPPFLAGS =-c -g -Wall -pedantic -Wextra CPPFLAGS =-c -g -Wall -pedantic -Wextra
LDFLAGS =-lSDL2 -lm -lSDL2main -lSDL2_image LDFLAGS =-lSDL2 -lm -lSDL2main -lSDL2_image
LDFLAGS +=-L/usr/local/lib -lSDL2_ttf LDFLAGS +=-L/usr/local/lib -lSDL2_ttf -lSDL2_net
INCFLAGS = -I. -Iinclude INCFLAGS = -I/usr/local/include/SDL2 -Iinclude
INC =include/ INC =include/
@@ -19,7 +19,7 @@ ifeq ($(debug),on)
CPPFLAGS += -Ddebug CPPFLAGS += -Ddebug
endif endif
BINARIES = game client_test server_test BINARIES = game client server
all : $(BINARIES) all : $(BINARIES)
@@ -63,6 +63,17 @@ $(OBJ)game.o : game.c $(INC)game.h | $(OBJ)
$(OBJ)overworld.o : overworld.c $(INC)overworld.h | $(OBJ) $(OBJ)overworld.o : overworld.c $(INC)overworld.h | $(OBJ)
$(CC) $(CPPFLAGS) -o $@ $< $(INCFLAGS) $(CC) $(CPPFLAGS) -o $@ $< $(INCFLAGS)
$(OBJ)net.o : net.c $(INC)net.h | $(OBJ)
$(CC) $(CPPFLAGS) -o $@ $< $(INCFLAGS)
$(OBJ)client.o : client.c $(INC)net.h | $(OBJ)
$(CC) $(CPPFLAGS) -o $@ $< $(INCFLAGS)
$(OBJ)server.o : server.c $(INC)net.h | $(OBJ)
$(CC) $(CPPFLAGS) -o $@ $< $(INCFLAGS)
## --- LIBRARY FILES --- ## --- LIBRARY FILES ---
@@ -73,14 +84,15 @@ $(OBJ)overworld.o : overworld.c $(INC)overworld.h | $(OBJ)
#$(BIN) : $(OBJ) | $(BIN) #$(BIN) : $(OBJ) | $(BIN)
# $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) # $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
$(BIN)client_test : $(OBJ)client_test.o | $(BIN) $(BIN)client : $(OBJ)client.o | $(BIN)
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
$(BIN)server_test: $(OBJ)server_test.o | $(BIN) $(BIN)server: $(OBJ)server.o | $(BIN)
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
$(BIN)game : $(OBJ)main.o $(OBJ)input.o $(OBJ)battle.o $(OBJ)game.o\ $(BIN)game : $(OBJ)main.o $(OBJ)input.o $(OBJ)battle.o $(OBJ)game.o\
$(OBJ)options.o $(OBJ)host.o $(OBJ)join.o $(OBJ)overworld.o | $(BIN) $(OBJ)options.o $(OBJ)host.o $(OBJ)join.o $(OBJ)overworld.o $(OBJ)net.o\
| $(BIN)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
$(BINARIES) : % : $(BIN)% $(BINARIES) : % : $(BIN)%

View File

@@ -7,18 +7,18 @@ DEPENDANCIES
SDL CORE: SDL CORE:
use SDL 2.24.x use SDL 2.24.x
https://github.com/libsdl-org/SDL.git git clone https://github.com/libsdl-org/SDL.git
cd SDL cd SDL
git checkout release-2.24.x git checkout release-2.24.x
mkdir build mkdir build
cd build cd build
cmake .. cmake .. -DCMAKE_POLICY_VERSION_MINIMUM=3.5
sudo make install sudo make install -j
SDL IMAGE: SDL IMAGE:
use SDL_Image 2.8.x use SDL_Image 2.8.x
https://github.com/libsdl-org/SDL_image.git git clone https://github.com/libsdl-org/SDL_image.git
cd SDL_image cd SDL_image
git checkout release-2.8.x git checkout release-2.8.x
mkdir build mkdir build
@@ -30,7 +30,7 @@ sudo make install
SDL_Net: SDL_Net:
use SDL_Net 2.2.x use SDL_Net 2.2.x
https://github.com/libsdl-org/SDL_net.git git clone https://github.com/libsdl-org/SDL_net.git
cd SDL_net cd SDL_net
git checkout release-2.2.x git checkout release-2.2.x
mkdir build mkdir build
@@ -41,7 +41,7 @@ sudo make install
SDL_ttf SDL_ttf
use SDL_ttf 2.24.x use SDL_ttf 2.24.x
https://github.com/libsdl-org/SDL_ttf.git git clone https://github.com/libsdl-org/SDL_ttf.git
cd SDL_ttf cd SDL_ttf
git checkout release-2.24.x git checkout release-2.24.x
mkdir build mkdir build

1
client Symbolic link
View File

@@ -0,0 +1 @@
build/bin/client

1
game Symbolic link
View File

@@ -0,0 +1 @@
build/bin/game

204
host.c
View File

@@ -17,27 +17,148 @@
int over_object; int over_object;
char player_names[MAX_PLAYERS][MAX_NAMESZ]; char player_names[MAX_PLAYERS][MAX_NAMESZ];
char last_sent_name[MAX_NAMESZ]; char temp_name[MAX_NAMESZ];
char lobby_name[MAX_NAMESZ];
char lobby_name_perm[MAX_NAMESZ];
int num_players = 1; int num_players = 1;
int lobby_has_name = 0;
SDL_Rect set_name_rect, name_rect, player_name_rect;
SDL_Rect player_rects[MAX_PLAYERS];
SDL_Rect player_name_rects[MAX_PLAYERS];
SDL_Rect start_rect;
TTF_Font* font;
SDL_Color white = {255, 255, 255, 0};
SDL_Surface *set_name_surf;
SDL_Surface *start_surf;
SDL_Surface *lobby_name_surf;
SDL_Texture *set_name_tex;
SDL_Texture *lobby_name_tex;
SDL_Texture *start_tex;
SDL_Surface *player_name_surfs[MAX_PLAYERS];
SDL_Surface *player_tempname_surf;
SDL_Texture *player_name_texs[MAX_PLAYERS];
SDL_Texture *player_tempname_tex;
char *get_this_name(int i) char *get_this_name(int i)
{ {
if(i >= 0 && i < MAX_PLAYERS){ return player_names[i]; }
if(!lobby_has_name) {
if(i == -1){return lobby_name; }
if(i == 0) { return lobby_name_perm; }
}
else{
if(i == -1) { return temp_name; }
if(i >= 0 && i < MAX_PLAYERS){
return player_names[i];
}
}
return NULL; return NULL;
} }
void render_lobby()
{
int i;
player_tempname_surf= TTF_RenderText_Solid(font, temp_name, white);
player_tempname_tex = SDL_CreateTextureFromSurface(renderer, player_tempname_surf);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//set name button
SDL_SetRenderDrawColor(renderer, 64, 64, 64,255);
SDL_RenderFillRect(renderer, &set_name_rect);
SDL_RenderCopy(renderer, set_name_tex, NULL, &(set_name_rect));
//player fields
for(i = 0; i < MAX_PLAYERS; i++)
{
player_name_rects[i].w = (player_rects[0].w / MAX_NAMESZ) * strlen(player_names[i]);
player_name_surfs[i] = TTF_RenderText_Solid(font, player_names[i], white);
player_name_texs[i] = SDL_CreateTextureFromSurface(renderer, player_name_surfs[i]);
SDL_RenderFillRect(renderer, &(player_rects[i]));
SDL_RenderCopy(renderer, player_name_texs[i], NULL, &(player_name_rects[i]));
}
//name field
player_name_rect.w = (name_rect.w / MAX_NAMESZ) * strlen(temp_name);
SDL_RenderFillRect(renderer, &name_rect);
SDL_RenderCopy(renderer, player_tempname_tex, NULL, &player_name_rect);
//start game button
SDL_RenderFillRect(renderer, &start_rect);
SDL_RenderCopy(renderer, start_tex, NULL, &(start_rect));
SDL_RenderPresent(renderer);
player_tempname_surf= TTF_RenderText_Solid(font, temp_name, white);
player_tempname_tex = SDL_CreateTextureFromSurface(renderer, player_tempname_surf);
SDL_FreeSurface(player_tempname_surf);
SDL_DestroyTexture(player_tempname_tex);
for(i = 0; i < MAX_PLAYERS; i++)
{
SDL_FreeSurface(player_name_surfs[i]);
SDL_DestroyTexture(player_name_texs[i]);
}
}
void render_lobby_name()
{
lobby_name_surf = TTF_RenderText_Solid(font, lobby_name, white);
lobby_name_tex = SDL_CreateTextureFromSurface(renderer, lobby_name_surf);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//set lobby name button
SDL_SetRenderDrawColor(renderer, 64, 64, 64,255);
SDL_RenderFillRect(renderer, &set_name_rect);
SDL_RenderCopy(renderer, set_name_tex, NULL, &(set_name_rect));
//name field
player_name_rect.w = (name_rect.w / MAX_NAMESZ) * strlen(lobby_name);
SDL_RenderFillRect(renderer, &name_rect);
SDL_RenderCopy(renderer, lobby_name_tex, NULL, &player_name_rect);
//start game button
SDL_RenderFillRect(renderer, &start_rect);
SDL_RenderCopy(renderer, start_tex, NULL, &(start_rect));
SDL_RenderPresent(renderer);
}
void render_main()
{
SDL_GetMouseState(&(mouse_pos.x), &(mouse_pos.y));
if(SDL_PointInRect(&mouse_pos, &start_rect)){
over_object = START_GAME_BUTTON;
}
else if(SDL_PointInRect(&mouse_pos, &set_name_rect)){
over_object = SET_NAME_BUTTON;
}
handle_event(&event);
if(lobby_has_name){ render_lobby(); }
else{ render_lobby_name(); }
}
void host_game(){ void host_game(){
int i; int i;
PRINT_M(HOST state) PRINT_M(HOST state)
SDL_Point mouse_pos;
SDL_Rect set_name_rect, name_rect, player_name_rect;
SDL_Rect player_rects[MAX_PLAYERS];
SDL_Rect player_name_rects[MAX_PLAYERS];
SDL_Rect start_rect;
over_object = NO_OBJECT; over_object = NO_OBJECT;
strcpy(player_names[0], "player_1"); strcpy(player_names[0], "player_1");
@@ -45,14 +166,13 @@ void host_game(){
strcpy(player_names[2], "no_player_3"); strcpy(player_names[2], "no_player_3");
strcpy(player_names[3], "no_player_4"); strcpy(player_names[3], "no_player_4");
TTF_Font* font = TTF_OpenFont("assets/font.ttf", 24); font = TTF_OpenFont("assets/font.ttf", 24);
SDL_Color white = {255, 255, 255, 0}; set_name_surf = TTF_RenderText_Solid(font, "set name", white);
SDL_Surface *set_name_surf = TTF_RenderText_Solid(font, "set name", white); start_surf = TTF_RenderText_Solid(font, "start game", white);
SDL_Surface *start_surf = TTF_RenderText_Solid(font, "start game", white); lobby_name_surf = TTF_RenderText_Solid(font, lobby_name, white);
SDL_Texture *set_name_tex = SDL_CreateTextureFromSurface(renderer, set_name_surf);
SDL_Texture *start_tex = SDL_CreateTextureFromSurface(renderer, start_surf);
set_name_tex = SDL_CreateTextureFromSurface(renderer, set_name_surf);
start_tex = SDL_CreateTextureFromSurface(renderer, start_surf);
set_name_rect.w = DEF_WINDOW_WIDTH >> 3; set_name_rect.w = DEF_WINDOW_WIDTH >> 3;
@@ -99,60 +219,10 @@ void host_game(){
SDL_StartTextInput(); SDL_StartTextInput();
SDL_SetTextInputRect(&name_rect); SDL_SetTextInputRect(&name_rect);
SDL_Surface *player_name_surfs[MAX_PLAYERS];
SDL_Texture *player_name_texs[MAX_PLAYERS];
while(running) while(running)
{ {
render_main();
SDL_GetMouseState(&(mouse_pos.x), &(mouse_pos.y));
if(SDL_PointInRect(&mouse_pos, &start_rect))
{
over_object = START_GAME_BUTTON;
}
else if(SDL_PointInRect(&mouse_pos, &set_name_rect))
{
over_object = SET_NAME_BUTTON;
}
handle_event(&event);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//set name button
SDL_SetRenderDrawColor(renderer, 64, 64, 64,255);
SDL_RenderFillRect(renderer, &set_name_rect);
SDL_RenderCopy(renderer, set_name_tex, NULL, &(set_name_rect));
//player fields
for(i = 0; i < MAX_PLAYERS; i++)
{
player_name_rects[i].w = (player_rects[0].w / MAX_NAMESZ) * strlen(player_names[i]);
player_name_surfs[i] = TTF_RenderText_Solid(font, player_names[i], white);
player_name_texs[i] = SDL_CreateTextureFromSurface(renderer, player_name_surfs[i]);
SDL_RenderFillRect(renderer, &(player_rects[i]));
SDL_RenderCopy(renderer, player_name_texs[i], NULL, &(player_name_rects[i]));
}
//name field
player_name_rect.w = (name_rect.w / MAX_NAMESZ) * strlen(player_names[0]);
SDL_RenderFillRect(renderer, &name_rect);
SDL_RenderCopy(renderer, player_name_texs[0], NULL, &player_name_rect);
//start game button
SDL_RenderFillRect(renderer, &start_rect);
SDL_RenderCopy(renderer, start_tex, NULL, &(start_rect));
SDL_RenderPresent(renderer);
for(i = 0; i < MAX_PLAYERS; i++)
{
SDL_FreeSurface(player_name_surfs[i]);
SDL_DestroyTexture(player_name_texs[i]);
}
} }
return; return;

View File

@@ -5,6 +5,7 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
extern SDL_Point mouse_pos;
#define TITLE 0 #define TITLE 0
#define START 1 #define START 1

View File

@@ -7,6 +7,8 @@
#define START_GAME_BUTTON 2 #define START_GAME_BUTTON 2
extern int over_object; extern int over_object;
extern int lobby_has_name;
char *get_this_name(int i); char *get_this_name(int i);

View File

@@ -1,12 +1,48 @@
//Troy Rosin //Troy Rosin
#ifndef __my_net_h__
#ifndef __netcode_h__ #define __my_net_h__
#define __netcode_h__
#define PORT 36911 #define PORT 36911
void init_network(); #define SERVER "localhost"
#define PACKSZ 1024
enum pack_type{
G_STATE, S_STATE, HOSTS_REQ, NEW_HOST, JOIN_REQ, U_NAME
};
typedef struct packet{
enum pack_type type;
char payload[PACKSZ - sizeof(enum pack_type)];
} packet;
int read_to_buff(Uint32 *buff, Uint32 *src, Uint32 sz)
{
if(sz%32){
puts("error size must be div by 32");
return 0;
}
for(Uint32 i = 0; i < (sz >> 2); i += 1)
{
*(buff + i) = SDLNet_Read32(src + i);
}
return 1;
}
int write_to_buff(Uint32 *buff, Uint32 *src, Uint32 sz)
{
if(sz%32){
puts("error size must be div by 32");
return 0;
}
for(Uint32 i = 0; i < (sz >> 2); i += 1)
{
SDLNet_Write32(*(src + i), (buff + i));
}
return 1;
}
#endif #endif

21
input.c
View File

@@ -153,10 +153,9 @@ void handle_input_host(SDL_Event *e)
{ {
int oldlen, inputlen; int oldlen, inputlen;
char tempname[MAX_NAMESZ], *nameptr; char tempname[MAX_NAMESZ], *nameptr;
nameptr = get_this_name(0); nameptr = get_this_name(-1);
strcpy(tempname, nameptr); strcpy(tempname, nameptr);
oldlen = strlen(tempname); oldlen = strlen(tempname);
inputlen = strlen(e->text.text);
switch(e->type) switch(e->type)
{ {
@@ -177,14 +176,26 @@ void handle_input_host(SDL_Event *e)
} }
break; break;
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
inputlen = strlen(e->text.text);
PRINT_M(got text input event) PRINT_M(got text input event)
if(oldlen + inputlen > MAX_NAMESZ -1){ break; } if(oldlen + inputlen > MAX_NAMESZ -1){ break; }
strcat(tempname, e->text.text); strcat(tempname, e->text.text);
strcpy(nameptr, tempname); strcpy(nameptr, tempname);
break; break;
case SDL_MOUSEBUTTONDOWN:
default: switch(over_object)
printf("got event type: %u\n", e->type); {
case NO_OBJECT:
break;
case SET_NAME_BUTTON:
strcpy(get_this_name(0), nameptr);
break;
case START_GAME_BUTTON:
if(strlen(get_this_name(0)) >= 1){
lobby_has_name = 1;
}
break;
}
} }
return; return;
} }

48
net.h
View File

@@ -1,48 +0,0 @@
//Troy Rosin
#ifndef __my_net_h__
#define __my_net_h__
#define PORT 36911
#define SERVER "localhost"
#define PACKSZ 1024
enum pack_type{
G_STATE, S_STATE, HOSTS_REQ, NEW_HOST, JOIN_REQ, U_NAME
};
typedef struct packet{
enum pack_type type;
char payload[PACKSZ - sizeof(enum pack_type)];
} packet;
int read_to_buff(Uint32 *buff, Uint32 *src, Uint32 sz)
{
if(sz%32){
puts("error size must be div by 32");
return 0;
}
for(Uint32 i = 0; i < (sz >> 2); i += 1)
{
*(buff + i) = SDLNet_Read32(src + i);
}
return 1;
}
int write_to_buff(Uint32 *buff, Uint32 *src, Uint32 sz)
{
if(sz%32){
puts("error size must be div by 32");
return 0;
}
for(Uint32 i = 0; i < (sz >> 2); i += 1)
{
SDLNet_Write32(*(src + i), (buff + i));
}
return 1;
}
#endif

1
server Symbolic link
View File

@@ -0,0 +1 @@
build/bin/server

View File

@@ -89,7 +89,6 @@ void game_server()
break; break;
case U_NAME: case U_NAME:
PRINT_M("got to update name state"); PRINT_M("got to update name state");
flag = 0;
break; break;
} }
} }
@@ -110,13 +109,11 @@ void game_server()
} }
} }
} }
return;
} }
SDLNet_TCP_Close(sock); SDLNet_TCP_Close(sock);
SDLNet_Quit(); SDLNet_Quit();
SDL_Quit(); SDL_Quit();
} }

View File

@@ -1,137 +0,0 @@
/*
** server.c -- a stream socket server demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
void sigchld_handler(int s)
{
(void)s; // quiet unused variable warning
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
// listen on sock_fd, new connection on new_fd
int sockfd, new_fd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address info
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
&sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}