Switch to OpenGL instead of SDL
This commit is contained in:
parent
c3e1cbe5b0
commit
bf07969ee9
23
.vscode/c_cpp_properties.json
vendored
Normal file
23
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Win32",
|
||||||
|
"includePath": [
|
||||||
|
"${default}",
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"C:/msys64/mingw64/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"_DEBUG",
|
||||||
|
"UNICODE",
|
||||||
|
"_UNICODE"
|
||||||
|
],
|
||||||
|
"windowsSdkVersion": "10.0.26100.0",
|
||||||
|
"cStandard": "c23",
|
||||||
|
"cppStandard": "c++20",
|
||||||
|
"intelliSenseMode": "windows-gcc-x64",
|
||||||
|
"compilerPath": "C:/Program Files/mingw64/bin/gcc.exe"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
39
Makefile
Normal file
39
Makefile
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Compiler
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
SRC_DIR = src
|
||||||
|
BUILD_DIR = build
|
||||||
|
OUT = main.exe
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
SRC = \
|
||||||
|
$(SRC_DIR)\main.c \
|
||||||
|
$(SRC_DIR)\net.c \
|
||||||
|
$(SRC_DIR)\event.c \
|
||||||
|
$(SRC_DIR)\player.c
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
OBJ = $(patsubst $(SRC_DIR)\%.c, $(BUILD_DIR)\%.o, $(SRC))
|
||||||
|
|
||||||
|
# Include and linker flags
|
||||||
|
INCLUDE_FLAGS = -IC:/msys64/mingw64/include
|
||||||
|
LIBS = -LC:/msys64/mingw64/lib -static -lws2_32 -lSDL2main -lSDL2 -lwinmm -limm32 -lole32 -loleaut32 -lversion -lsetupapi -lgdi32 -lshell32 -luser32 -mconsole
|
||||||
|
CFLAGS = -Wall -Wextra -g $(INCLUDE_FLAGS)
|
||||||
|
LDFLAGS = $(LIBS)
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: $(OUT)
|
||||||
|
|
||||||
|
$(OUT): $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
# Compile each .c into .o
|
||||||
|
$(BUILD_DIR)\%.o: $(SRC_DIR)\%.c
|
||||||
|
@if not exist $(BUILD_DIR) mkdir $(BUILD_DIR)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
# Clean
|
||||||
|
clean:
|
||||||
|
del /Q $(BUILD_DIR)\*.o 2>nul || exit 0
|
||||||
|
del /Q $(OUT) 2>nul || exit 0
|
14
src/event.c
Normal file
14
src/event.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
#define MAX_HANDLERS 256
|
||||||
|
static PacketHandler g_handlers[MAX_HANDLERS] = {0};
|
||||||
|
|
||||||
|
void register_handler(uint8_t type, PacketHandler handler) {
|
||||||
|
g_handlers[type] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_packet(Packet* pkt, SOCKET client) {
|
||||||
|
if (g_handlers[pkt->type]) {
|
||||||
|
g_handlers[pkt->type](pkt, client);
|
||||||
|
}
|
||||||
|
}
|
15
src/event.h
Normal file
15
src/event.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef EVENT_H
|
||||||
|
#define EVENT_H
|
||||||
|
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
// Each handler receives Packet* and the client socket
|
||||||
|
typedef void (*PacketHandler)(Packet*, SOCKET client);
|
||||||
|
|
||||||
|
// Register a handler for a certain PacketType
|
||||||
|
void register_handler(uint8_t type, PacketHandler handler);
|
||||||
|
|
||||||
|
// Dispatch a packet
|
||||||
|
void handle_packet(Packet* pkt, SOCKET client);
|
||||||
|
|
||||||
|
#endif
|
336
src/main.c
Normal file
336
src/main.c
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define SDL_MAIN_HANDLED
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <windows.h> // Sleep()
|
||||||
|
#include "net.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
CRITICAL_SECTION g_playerLock;
|
||||||
|
static Player g_players[MAX_PLAYERS];
|
||||||
|
static int g_numPlayers = 0;
|
||||||
|
static SOCKET g_clients[MAX_CLIENTS];
|
||||||
|
static int g_clientCount = 0;
|
||||||
|
|
||||||
|
static uint32_t g_nextID = 1; // to assign unique IDs
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
DWORD WINAPI client_thread(LPVOID param);
|
||||||
|
void broadcast_packet(Packet* pkt, SOCKET except);
|
||||||
|
|
||||||
|
|
||||||
|
void on_player_move(Packet* pkt, SOCKET client) {
|
||||||
|
PlayerMove pm;
|
||||||
|
memcpy(&pm, pkt->data, sizeof(PlayerMove));
|
||||||
|
|
||||||
|
EnterCriticalSection(&g_playerLock);
|
||||||
|
for(int i = 0; i < g_numPlayers; i++) {
|
||||||
|
if(g_players[i].id == pm.id) {
|
||||||
|
g_players[i].x += pm.dx;
|
||||||
|
g_players[i].y += pm.dy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// broadcast updated positions
|
||||||
|
int numStates = g_numPlayers;
|
||||||
|
int dataSize = sizeof(PlayerState) * numStates;
|
||||||
|
PlayerState* states = malloc(dataSize);
|
||||||
|
for(int i = 0; i < g_numPlayers; i++) {
|
||||||
|
states[i].id = g_players[i].id;
|
||||||
|
states[i].x = g_players[i].x;
|
||||||
|
states[i].y = g_players[i].y;
|
||||||
|
}
|
||||||
|
Packet* statePkt = create_packet(PACKET_PLAYER_STATE, states, dataSize);
|
||||||
|
free(states);
|
||||||
|
broadcast_packet(statePkt, INVALID_SOCKET);
|
||||||
|
destroy_packet(statePkt);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&g_playerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void broadcast_packet(Packet* pkt, SOCKET except) {
|
||||||
|
// serialize
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
int len = serialize_packet(pkt, buffer);
|
||||||
|
|
||||||
|
EnterCriticalSection(&g_playerLock);
|
||||||
|
for(int i = 0; i < g_clientCount; i++) {
|
||||||
|
if(g_clients[i] == except) continue;
|
||||||
|
send(g_clients[i], buffer, len, 0);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&g_playerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI client_thread(LPVOID param) {
|
||||||
|
SOCKET client = *(SOCKET*)param;
|
||||||
|
free(param);
|
||||||
|
|
||||||
|
// Non-blocking for easier single-thread dispatch or we do blocking in a thread
|
||||||
|
set_socket_nonblocking(client, 0); // blocking in this thread
|
||||||
|
|
||||||
|
// Assign a new player
|
||||||
|
Player newPlayer;
|
||||||
|
newPlayer.id = g_nextID++;
|
||||||
|
newPlayer.x = 100; // start at 100,100
|
||||||
|
newPlayer.y = 100;
|
||||||
|
|
||||||
|
EnterCriticalSection(&g_playerLock);
|
||||||
|
g_players[g_numPlayers++] = newPlayer;
|
||||||
|
g_clients[g_clientCount++] = client;
|
||||||
|
LeaveCriticalSection(&g_playerLock);
|
||||||
|
|
||||||
|
printf("[SERVER] Client %u connected.\n", newPlayer.id);
|
||||||
|
|
||||||
|
// Now run receive loop
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
while(1) {
|
||||||
|
int received = recv(client, buffer, BUFFER_SIZE, 0);
|
||||||
|
if (received <= 0) {
|
||||||
|
break; // client disconnected
|
||||||
|
}
|
||||||
|
Packet* pkt = deserialize_packet(buffer, received);
|
||||||
|
if (pkt) {
|
||||||
|
// Dispatch
|
||||||
|
handle_packet(pkt, client);
|
||||||
|
destroy_packet(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from global state
|
||||||
|
EnterCriticalSection(&g_playerLock);
|
||||||
|
// remove from g_clients
|
||||||
|
for(int i = 0; i < g_clientCount; i++) {
|
||||||
|
if(g_clients[i] == client) {
|
||||||
|
g_clients[i] = g_clients[--g_clientCount];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove from g_players
|
||||||
|
for(int i = 0; i < g_numPlayers; i++) {
|
||||||
|
if(g_players[i].id == newPlayer.id) {
|
||||||
|
g_players[i] = g_players[--g_numPlayers];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&g_playerLock);
|
||||||
|
|
||||||
|
closesocket(client);
|
||||||
|
printf("[SERVER] Client %u disconnected.\n", newPlayer.id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_server(int port) {
|
||||||
|
net_init();
|
||||||
|
InitializeCriticalSection(&g_playerLock);
|
||||||
|
|
||||||
|
// Register server handlers
|
||||||
|
register_handler(PACKET_PLAYER_MOVE, on_player_move);
|
||||||
|
|
||||||
|
SOCKET server = net_bind_and_listen(port);
|
||||||
|
if (server == INVALID_SOCKET) {
|
||||||
|
printf("Failed to bind on port %d\n", port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("[SERVER] Listening on port %d...\n", port);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
SOCKET s = net_accept(server);
|
||||||
|
if (s == INVALID_SOCKET) {
|
||||||
|
Sleep(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Start a client thread
|
||||||
|
SOCKET* ptr = malloc(sizeof(SOCKET));
|
||||||
|
*ptr = s;
|
||||||
|
CreateThread(NULL, 0, client_thread, ptr, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteCriticalSection(&g_playerLock);
|
||||||
|
closesocket(server);
|
||||||
|
net_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Player g_localPlayer = {0};
|
||||||
|
static PlayerState g_otherPlayers[MAX_PLAYERS];
|
||||||
|
static int g_otherCount = 0;
|
||||||
|
|
||||||
|
// For now, store the socket globally
|
||||||
|
static SOCKET g_sock = INVALID_SOCKET;
|
||||||
|
|
||||||
|
// Handler: PACKET_PLAYER_STATE
|
||||||
|
void on_player_state(Packet* pkt, SOCKET _) {
|
||||||
|
// We'll parse an array of PlayerStates
|
||||||
|
int num = pkt->size / sizeof(PlayerState);
|
||||||
|
if(num > MAX_PLAYERS) num = MAX_PLAYERS;
|
||||||
|
|
||||||
|
memcpy(g_otherPlayers, pkt->data, pkt->size);
|
||||||
|
g_otherCount = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_client(const char* ip, int port) {
|
||||||
|
net_init();
|
||||||
|
|
||||||
|
// Register client handlers
|
||||||
|
register_handler(PACKET_PLAYER_STATE, on_player_state);
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
g_sock = net_connect(ip, port);
|
||||||
|
if (g_sock == INVALID_SOCKET) {
|
||||||
|
printf("[CLIENT] Could not connect to server.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("[CLIENT] Connected to server %s:%d\n", ip, port);
|
||||||
|
|
||||||
|
// We'll assign an ID after reading from server in a real scenario,
|
||||||
|
// but for simplicity, let's guess the server will do so.
|
||||||
|
// We'll just store local ID = 999, or we wait for some handshake.
|
||||||
|
// For now, let's store a random number:
|
||||||
|
g_localPlayer.id = 9999;
|
||||||
|
g_localPlayer.x = 200;
|
||||||
|
g_localPlayer.y = 200;
|
||||||
|
|
||||||
|
// Setup SDL
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||||
|
printf("SDL_Init failed: %s\n", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window* window = SDL_CreateWindow(
|
||||||
|
"MPGC Client",
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
800, 600,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if(!window) {
|
||||||
|
printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
if(!renderer) {
|
||||||
|
printf("SDL_CreateRenderer failed: %s\n", SDL_GetError());
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-blocking so we can poll in main loop
|
||||||
|
set_socket_nonblocking(g_sock, 1);
|
||||||
|
|
||||||
|
int running = 1;
|
||||||
|
while (running) {
|
||||||
|
// ---- Handle SDL events
|
||||||
|
SDL_Event e;
|
||||||
|
while(SDL_PollEvent(&e)) {
|
||||||
|
if(e.type == SDL_QUIT) {
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Keyboard input (WASD)
|
||||||
|
const Uint8* state = SDL_GetKeyboardState(NULL);
|
||||||
|
float dx = 0.f;
|
||||||
|
float dy = 0.f;
|
||||||
|
if(state[SDL_SCANCODE_W]) { dy -= 2.f; }
|
||||||
|
if(state[SDL_SCANCODE_S]) { dy += 2.f; }
|
||||||
|
if(state[SDL_SCANCODE_A]) { dx -= 2.f; }
|
||||||
|
if(state[SDL_SCANCODE_D]) { dx += 2.f; }
|
||||||
|
|
||||||
|
if(dx != 0 || dy != 0) {
|
||||||
|
// Move local player
|
||||||
|
g_localPlayer.x += dx;
|
||||||
|
g_localPlayer.y += dy;
|
||||||
|
|
||||||
|
// Send PACKET_PLAYER_MOVE
|
||||||
|
PlayerMove pm;
|
||||||
|
pm.id = g_localPlayer.id;
|
||||||
|
pm.dx = dx;
|
||||||
|
pm.dy = dy;
|
||||||
|
|
||||||
|
Packet* movePkt = create_packet(PACKET_PLAYER_MOVE, &pm, sizeof(pm));
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
int len = serialize_packet(movePkt, buffer);
|
||||||
|
send(g_sock, buffer, len, 0);
|
||||||
|
destroy_packet(movePkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Check for incoming data
|
||||||
|
while (1) {
|
||||||
|
char netbuf[BUFFER_SIZE];
|
||||||
|
int r = recv(g_sock, netbuf, BUFFER_SIZE, 0);
|
||||||
|
if (r <= 0) break; // no data or error
|
||||||
|
Packet* pkt = deserialize_packet(netbuf, r);
|
||||||
|
if(pkt) {
|
||||||
|
handle_packet(pkt, g_sock);
|
||||||
|
destroy_packet(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Render scene
|
||||||
|
SDL_SetRenderDrawColor(renderer, 20, 20, 20, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
// Draw local player
|
||||||
|
SDL_Rect rLoc = {
|
||||||
|
(int)g_localPlayer.x,
|
||||||
|
(int)g_localPlayer.y,
|
||||||
|
30, 30
|
||||||
|
};
|
||||||
|
SDL_SetRenderDrawColor(renderer, 200, 200, 50, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &rLoc);
|
||||||
|
|
||||||
|
// Draw other players
|
||||||
|
SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);
|
||||||
|
for(int i = 0; i < g_otherCount; i++) {
|
||||||
|
SDL_Rect rOth = {
|
||||||
|
(int)g_otherPlayers[i].x,
|
||||||
|
(int)g_otherPlayers[i].y,
|
||||||
|
30, 30
|
||||||
|
};
|
||||||
|
SDL_RenderFillRect(renderer, &rOth);
|
||||||
|
}
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
closesocket(g_sock);
|
||||||
|
net_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
printf("[INFO] Starting...\n");
|
||||||
|
SDL_SetMainReady();
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Usage:\n %s server <port>\n %s client <ip> <port>\n", argv[0], argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(strcmp(argv[1], "server") == 0) {
|
||||||
|
int port = atoi(argv[2]);
|
||||||
|
run_server(port);
|
||||||
|
printf("[SERVER] Listening on port %d\n", port);
|
||||||
|
} else if(strcmp(argv[1], "client") == 0 && argc >= 4) {
|
||||||
|
const char* ip = argv[2];
|
||||||
|
int port = atoi(argv[3]);
|
||||||
|
run_client(ip, port);
|
||||||
|
} else {
|
||||||
|
printf("Invalid arguments.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
78
src/net.c
Normal file
78
src/net.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "net.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
|
||||||
|
Packet* create_packet(PacketType type, const void* data, uint16_t size) {
|
||||||
|
Packet* pkt = malloc(sizeof(Packet) + size);
|
||||||
|
pkt->type = type;
|
||||||
|
pkt->size = size;
|
||||||
|
memcpy(pkt->data, data, size);
|
||||||
|
return pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int serialize_packet(Packet* pkt, char* buffer) {
|
||||||
|
buffer[0] = pkt->type;
|
||||||
|
buffer[1] = (pkt->size >> 8) & 0xFF;
|
||||||
|
buffer[2] = pkt->size & 0xFF;
|
||||||
|
memcpy(buffer + 3, pkt->data, pkt->size);
|
||||||
|
return 3 + pkt->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet* deserialize_packet(const char* buffer, int len) {
|
||||||
|
if (len < 3) return NULL;
|
||||||
|
uint8_t type = buffer[0];
|
||||||
|
uint16_t size = ((uint8_t)buffer[1] << 8) | (uint8_t)buffer[2];
|
||||||
|
if (size > len - 3) return NULL;
|
||||||
|
return create_packet(type, buffer + 3, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_packet(Packet* pkt) {
|
||||||
|
free(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void net_init() {
|
||||||
|
WSADATA wsa;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &wsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
void net_cleanup() {
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET net_connect(const char* ip, int port) {
|
||||||
|
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
struct sockaddr_in addr = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = htons(port)
|
||||||
|
};
|
||||||
|
inet_pton(AF_INET, ip, &addr.sin_addr);
|
||||||
|
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET net_bind_and_listen(int port) {
|
||||||
|
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
struct sockaddr_in addr = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = htons(port),
|
||||||
|
.sin_addr.s_addr = INADDR_ANY
|
||||||
|
};
|
||||||
|
bind(server, (struct sockaddr*)&addr, sizeof(addr));
|
||||||
|
listen(server, SOMAXCONN);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET net_accept(SOCKET server) {
|
||||||
|
return accept(server, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_socket_nonblocking(SOCKET sock, int enable)
|
||||||
|
{
|
||||||
|
u_long mode = (enable) ? 1 : 0;
|
||||||
|
ioctlsocket(sock, FIONBIO, &mode);
|
||||||
|
}
|
40
src/net.h
Normal file
40
src/net.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef NET_H
|
||||||
|
#define NET_H
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MAX_CLIENTS 64
|
||||||
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PACKET_PING = 1,
|
||||||
|
PACKET_TEXT,
|
||||||
|
PACKET_CLIENT_JOINED,
|
||||||
|
PACKET_CLIENT_LEFT,
|
||||||
|
PACKET_PLAYER_MOVE,
|
||||||
|
PACKET_PLAYER_STATE,
|
||||||
|
PACKET_MAX
|
||||||
|
} PacketType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t size;
|
||||||
|
char data[];
|
||||||
|
} Packet;
|
||||||
|
|
||||||
|
Packet* create_packet(PacketType type, const void* data, uint16_t size);
|
||||||
|
int serialize_packet(Packet* pkt, char* buffer);
|
||||||
|
Packet* deserialize_packet(const char* buffer, int len);
|
||||||
|
void destroy_packet(Packet* pkt);
|
||||||
|
|
||||||
|
// Networking setup
|
||||||
|
void net_init();
|
||||||
|
void net_cleanup();
|
||||||
|
SOCKET net_connect(const char* ip, int port);
|
||||||
|
SOCKET net_bind_and_listen(int port);
|
||||||
|
SOCKET net_accept(SOCKET server);
|
||||||
|
void set_socket_nonblocking(SOCKET sock, int enable);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
2
src/player.c
Normal file
2
src/player.c
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "player.h"
|
||||||
|
|
25
src/player.h
Normal file
25
src/player.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef PLAYER_H
|
||||||
|
#define PLAYER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
float x, y;
|
||||||
|
} Player;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
float dx;
|
||||||
|
float dy;
|
||||||
|
} PlayerMove;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} PlayerState;
|
||||||
|
|
||||||
|
#define MAX_PLAYERS 64
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user