TCP networking
This commit is contained in:
@@ -238,6 +238,10 @@
|
||||
// only valid if there's an in-scope variable bool `debug_mode`
|
||||
#define dbg(fmt, ...) osDebugPrint(debug_mode, fmt, ##__VA_ARGS__)
|
||||
|
||||
///// SYSTEM INCLUDES I always want
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
///// TYPES
|
||||
// integer types
|
||||
typedef unsigned char u8;
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "all.h"
|
||||
|
||||
global pthread_barrier_t linux_thread_barrier;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "all.h"
|
||||
#include "pthread_barrier.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "string.h"
|
||||
#include <userenv.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static u64 w32_ticks_per_sec = 1;
|
||||
static u32 w32_thread_context_index;
|
||||
|
||||
+70
-78
@@ -13,9 +13,6 @@
|
||||
#include "lib/network.c"
|
||||
#include "lib/tui.c"
|
||||
#include "string_chunk.c"
|
||||
//#include "assets/asset1.h"
|
||||
//#include "assets/asset2.h"
|
||||
//#include "assets/asset3.h"
|
||||
|
||||
///// #define a bunch of client-only tunable game constants
|
||||
#define SYSTEM_MESSAGES_LEN 32
|
||||
@@ -167,8 +164,7 @@ typedef struct GameState {
|
||||
MenuState menu;
|
||||
MenuState row; // for tracking which row of a table the user has selected
|
||||
MenuState modal_choice;
|
||||
UDPMessage keep_alive_msg;
|
||||
UDPClient client;
|
||||
TCPClient client;
|
||||
StringChunkList message_input;
|
||||
StarSystem map[STAR_SYSTEM_COUNT];
|
||||
Pos2 pos;
|
||||
@@ -277,23 +273,6 @@ fn void renderSystemMessages(Pixel* buf, Dim2 screen_dimensions, Box sys_msg_box
|
||||
}
|
||||
}
|
||||
|
||||
fn void renderStaticAssetToPixelBuffer(TuiState* tui, u8* asset, u32 len, u16 x, u16 y) {
|
||||
u16 line = 0;
|
||||
u16 x_in_line = 0;
|
||||
u16 pos = x + (tui->screen_dimensions.width * y);
|
||||
for (u32 i = 0; i < len; i++, x_in_line++) {
|
||||
if (asset[i] == '\n') {
|
||||
line += 1;
|
||||
x_in_line = 0;
|
||||
pos = x + (tui->screen_dimensions.width * (y+line));
|
||||
} else if (asset[i] == ' ') {
|
||||
// do nothing, we skip spaces in our assets
|
||||
} else {
|
||||
tui->frame_buffer[pos+x_in_line].bytes[0] = asset[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void resetTabRow(Tab tab) {
|
||||
if (state.menu.selected_index == TabMarket) {
|
||||
state.market_tab_state = MarketTabStateTable;
|
||||
@@ -339,10 +318,17 @@ fn void moveRowUpDown(bool user_pressed_up, bool user_pressed_down) {
|
||||
}
|
||||
}
|
||||
|
||||
fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) {
|
||||
fn void handleIncomingMessage(u8* message, i32 len) {
|
||||
assert(len >= 0); // TODO actually handle this error
|
||||
u64 msg_pos = 0;
|
||||
Message msg_type = message[msg_pos++];
|
||||
dbg("handleIncomingMessage() of len=%d, message=%s\n", len, MESSAGE_STRINGS[msg_type]);
|
||||
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "handleIncomingMessage() of len=%d, message=%s\n", len, MESSAGE_STRINGS[msg_type]);
|
||||
if (msg_type != MessageSystemPassengers && msg_type != MessageSystemCommodities) {
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
|
||||
u8List bytes = {len, len, message};
|
||||
ParsedServerMessage parsed = {0};
|
||||
parsed.type = msg_type;
|
||||
@@ -462,29 +448,24 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
|
||||
psmThreadSafeQueuePush(network_recv_queue, &parsed);
|
||||
}
|
||||
|
||||
fn void* receiveNetworkUpdates(void* udp) {
|
||||
UDPClient client = *(UDPClient*)udp;
|
||||
fn void* receiveNetworkUpdates(void* net_client) {
|
||||
TCPClient client = *(TCPClient*)net_client;
|
||||
dbg("receiveNetworkUpdates() sock=%d\n", client.socket);
|
||||
UDPServer server = {
|
||||
.ready = true,
|
||||
.server_address = client.server_address,
|
||||
.server_socket = client.socket
|
||||
};
|
||||
infiniteReadUDPServer(&server, handleIncomingMessage);
|
||||
infiniteReadTCPClient(client.socket, &should_quit, handleIncomingMessage, addSystemMessage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void* sendNetworkUpdates(void* udp) {
|
||||
i32 socket_fd = ((UDPClient*)udp)->socket;
|
||||
dbg("sendNetworkUpdates() sock=%d\n", socket_fd);
|
||||
u8List bytes_list = {0};
|
||||
fn void* sendNetworkUpdates(void* net_client) {
|
||||
TCPClient* client = (TCPClient*)net_client;
|
||||
dbg("sendNetworkUpdates() sock=%d\n", client->socket);
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.socket_fd = client->socket,
|
||||
.address = client->server_address,
|
||||
};
|
||||
while (!should_quit) {
|
||||
UDPMessage msg = {0};
|
||||
outgoingMessageQueuePop(network_send_queue, &msg);
|
||||
bytes_list.items = msg.bytes;
|
||||
bytes_list.length = msg.bytes_len;
|
||||
bytes_list.capacity = msg.bytes_len;
|
||||
sendUDPu8List(socket_fd, &msg.address, &bytes_list);
|
||||
sendTCPMessage(msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -528,15 +509,16 @@ fn Box defaultModal(TuiState* tui) {
|
||||
return modal_outline;
|
||||
}
|
||||
|
||||
fn void sendLoginCommand(SocketAddress addr, u16 client_port) {
|
||||
fn void sendLoginCommand(TCPClient* net_client) {
|
||||
u32 msg_idx = 0;
|
||||
// drop the login message into the network_send_queue
|
||||
UDPMessage msg = { .address = addr };
|
||||
NetworkMessage msg = { .use_socket = true, .socket_fd = net_client->socket, .address = net_client->server_address };
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[msg_idx++] = CommandLogin;
|
||||
// 2. our LAN-IP to handle the case where we are on the same LAN as the guy we are trying to fight
|
||||
// and our "listened" UDP port
|
||||
msg_idx += writeU16ToBufferLE(msg.bytes + msg_idx, ~client_port);
|
||||
//msg_idx += writeU16ToBufferLE(msg.bytes + msg_idx, ~client_port);
|
||||
msg_idx += writeU16ToBufferLE(msg.bytes + msg_idx, 9999); // we aren't actually doing this right now
|
||||
msg_idx += writeI32ToBufferLE(msg.bytes + msg_idx, ~osLanIPAddress());
|
||||
// 2. how long is the name
|
||||
msg.bytes[msg_idx++] = state.login_state.name.length;
|
||||
@@ -551,7 +533,6 @@ fn void sendLoginCommand(SocketAddress addr, u16 client_port) {
|
||||
fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count) {
|
||||
GameState* state = (GameState*) s;
|
||||
state->loop_count = loop_count;
|
||||
UDPClient* udp = &state->client;
|
||||
state->old_screen = state->screen;
|
||||
Dim2 screen_dimensions = tui->screen_dimensions;
|
||||
bool game_screen_changed = state->old_screen != state->screen; // detect new screens
|
||||
@@ -594,7 +575,7 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
// auto-re-login
|
||||
if (state->me.base_cost > 0) {
|
||||
addSystemMessage((u8*)"auto re logging in due to MessageNotAlive");
|
||||
sendLoginCommand(udp->server_address, udp->client_port);
|
||||
sendLoginCommand(&state->client);
|
||||
state->screen = ScreenLogin;
|
||||
state->login_state.state = LoginScreenStateLoading;
|
||||
}
|
||||
@@ -859,9 +840,12 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
state->me.remaining_mortgage = template.base_cost - STARTING_DOWN_PAYMENT;
|
||||
state->me.interest_rate = calcInterestRate(template.base_cost, STARTING_DOWN_PAYMENT);
|
||||
// send character ship details to server
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
msg.bytes_len = 2;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
.bytes_len = 2,
|
||||
};
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[0] = CommandCreateCharacter;
|
||||
// 2. chosen ShipType
|
||||
@@ -1114,14 +1098,16 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
state->destination_sys_idx = i;
|
||||
// send the destination to the server
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[msg_idx++] = CommandSetDestination;
|
||||
// 2. buy?
|
||||
msg.bytes[msg_idx++] = state->destination_sys_idx;
|
||||
msg.bytes_len = msg_idx;
|
||||
|
||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
||||
}
|
||||
}
|
||||
@@ -1186,14 +1172,16 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
if (user_pressed_enter && state->ship_tab_states == ShipTabStateMain) {
|
||||
// send the "ready" or "not ready" message to the server
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[msg_idx++] = CommandReadyStatus;
|
||||
// 2. buy?
|
||||
msg.bytes[msg_idx++] = !state->me.ready_to_depart;
|
||||
msg.bytes_len = msg_idx;
|
||||
|
||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
||||
}
|
||||
}
|
||||
@@ -1276,14 +1264,16 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
if (user_pressed_enter) {
|
||||
// send the "payoff" message to server
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[msg_idx++] = CommandPayMortgage;
|
||||
// 2. buy?
|
||||
msg_idx += writeU64ToBufferLE(msg.bytes + msg_idx, input_quantity);
|
||||
msg.bytes_len = msg_idx;
|
||||
|
||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
||||
|
||||
state->ship_tab_states = ShipTabStateLoading;
|
||||
@@ -1344,8 +1334,11 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
if (user_pressed_enter) {
|
||||
// send the "buy this auction" message to the server
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
msg.bytes[msg_idx++] = CommandBuyAuction;
|
||||
msg.bytes_len = msg_idx;
|
||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
||||
@@ -1550,8 +1543,11 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
// send the "purchase" or "sell" message to server
|
||||
// get back new "status" of things
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
// 1. msg type/CommandType
|
||||
msg.bytes[msg_idx++] = CommandTransact;
|
||||
// 2. buy?
|
||||
@@ -1561,7 +1557,6 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
// 4. commodity
|
||||
msg.bytes[msg_idx++] = selected_commodity.type;
|
||||
msg.bytes_len = msg_idx;
|
||||
|
||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
||||
|
||||
state->market_tab_state = MarketTabStateLoading;
|
||||
@@ -1701,8 +1696,11 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
// send the "job accept" message to server
|
||||
// get back new "status" of things
|
||||
u32 msg_idx = 0;
|
||||
UDPMessage msg = {0};
|
||||
msg.address = udp->server_address;
|
||||
NetworkMessage msg = {
|
||||
.use_socket = true,
|
||||
.address = state->client.server_address,
|
||||
.socket_fd = state->client.socket,
|
||||
};
|
||||
msg.bytes[msg_idx++] = CommandAcceptPassengerJob;
|
||||
msg.bytes[msg_idx++] = current_row.goal_system_idx;
|
||||
msg.bytes[msg_idx++] = current_row.people;
|
||||
@@ -1787,7 +1785,7 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
state->login_state.selected_field = 1;
|
||||
state->login_state.field_index = 0;
|
||||
} else {
|
||||
sendLoginCommand(udp->server_address, udp->client_port);
|
||||
sendLoginCommand(&state->client);
|
||||
// show loading signal, stop accepting input
|
||||
state->login_state.state = LoginScreenStateLoading;
|
||||
addSystemMessage((u8*)state->login_state.name.bytes);
|
||||
@@ -1867,11 +1865,6 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
|
||||
break;
|
||||
}
|
||||
|
||||
if (loop_count % 10 == 0) {
|
||||
outgoingMessageQueuePush(network_send_queue, &state->keep_alive_msg);
|
||||
//outgoingMessageQueuePush(network_send_queue, &testm);
|
||||
}
|
||||
|
||||
return should_quit;
|
||||
}
|
||||
|
||||
@@ -1913,23 +1906,22 @@ i32 main(i32 argc, ptr argv[]) {
|
||||
exit(1);
|
||||
}
|
||||
ptr server_address = NULL;
|
||||
char input_string[16] = { 0 };
|
||||
if (argc > 1) {
|
||||
server_address = argv[1];
|
||||
} else {
|
||||
printf("Server IP Address: ");
|
||||
char input_string[16] = { 0 };
|
||||
scanf("%15s", input_string);
|
||||
printf("%s", input_string);
|
||||
if (input_string[0] && input_string[1] && input_string[2] && input_string[3]) {
|
||||
server_address = input_string;
|
||||
}
|
||||
}
|
||||
state.client = createUDPClient(7777, server_address);
|
||||
|
||||
// "hardcoded" keep alive message to periodically send to server
|
||||
state.keep_alive_msg.address = state.client.server_address;
|
||||
state.keep_alive_msg.bytes[0] = CommandKeepAlive;
|
||||
state.keep_alive_msg.bytes_len = 1;
|
||||
state.client = createTCPClient(SERVER_PORT, server_address);
|
||||
if (!state.client.ready) {
|
||||
printf("network could not connect() to server");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Thread recv_thread = spawnThread(&receiveNetworkUpdates, &state.client);
|
||||
Thread send_thread = spawnThread(&sendNetworkUpdates, &state.client);
|
||||
|
||||
+295
-19
@@ -1,4 +1,5 @@
|
||||
#include "../base/all.h"
|
||||
#include <poll.h>
|
||||
|
||||
// https://stackoverflow.com/questions/1098897/what-is-the-largest-safe-udp-packet-size-on-the-internet
|
||||
#define UDP_MAX_MESSAGE_LEN 508
|
||||
@@ -6,14 +7,42 @@
|
||||
#define NET_OUTGOING_MESSAGE_QUEUE_LEN 16
|
||||
#endif
|
||||
|
||||
#ifndef NET_SERVER_MAX_CLIENTS
|
||||
#define NET_SERVER_MAX_CLIENTS (16)
|
||||
#endif
|
||||
|
||||
typedef struct sockaddr_in SocketAddress;
|
||||
|
||||
typedef struct MultiServer {
|
||||
bool ready;
|
||||
i32 udp_socket_fd;
|
||||
i32 tcp_socket_fd;
|
||||
SocketAddress address;
|
||||
} MultiServer;
|
||||
|
||||
typedef struct TCPServer {
|
||||
bool ready;
|
||||
i32 socket_fd;
|
||||
SocketAddress address;
|
||||
} TCPServer;
|
||||
|
||||
typedef struct UDPServer {
|
||||
bool ready;
|
||||
SocketAddress server_address;
|
||||
i32 server_socket;
|
||||
} UDPServer;
|
||||
|
||||
typedef struct ServableUDPInfo {
|
||||
UDPServer server;
|
||||
void (*callback)(u8* udp_message, u32 udp_len, SocketAddress sending_address, i32 socket);
|
||||
} ServableUDPInfo;
|
||||
|
||||
typedef struct TCPClient {
|
||||
bool ready;
|
||||
SocketAddress server_address;
|
||||
i32 socket;
|
||||
} TCPClient;
|
||||
|
||||
typedef struct UDPClient {
|
||||
bool ready;
|
||||
SocketAddress server_address;
|
||||
@@ -21,14 +50,16 @@ typedef struct UDPClient {
|
||||
i32 socket;
|
||||
} UDPClient;
|
||||
|
||||
typedef struct UDPMessage {
|
||||
typedef struct NetworkMessage {
|
||||
bool use_socket; // default = false = UDP, just sendto(address)
|
||||
u16 bytes_len;
|
||||
SocketAddress address;
|
||||
i32 socket_fd;
|
||||
u8 bytes[UDP_MAX_MESSAGE_LEN];
|
||||
} UDPMessage;
|
||||
} NetworkMessage;
|
||||
|
||||
typedef struct OutgoingMessageQueue {
|
||||
UDPMessage items[NET_OUTGOING_MESSAGE_QUEUE_LEN];
|
||||
NetworkMessage items[NET_OUTGOING_MESSAGE_QUEUE_LEN];
|
||||
u32 head;
|
||||
u32 tail;
|
||||
u32 count;
|
||||
@@ -46,7 +77,7 @@ fn OutgoingMessageQueue* newOutgoingMessageQueue(Arena* a) {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void outgoingMessageQueuePush(OutgoingMessageQueue* queue, UDPMessage* msg) {
|
||||
fn void outgoingMessageQueuePush(OutgoingMessageQueue* queue, NetworkMessage* msg) {
|
||||
lockMutex(&queue->mutex); {
|
||||
while (queue->count == NET_OUTGOING_MESSAGE_QUEUE_LEN) {
|
||||
waitForCondSignal(&queue->not_full, &queue->mutex);
|
||||
@@ -60,11 +91,11 @@ fn void outgoingMessageQueuePush(OutgoingMessageQueue* queue, UDPMessage* msg) {
|
||||
} unlockMutex(&queue->mutex);
|
||||
}
|
||||
|
||||
fn UDPMessage* outgoingMessageNonblockingQueuePop(OutgoingMessageQueue* q, UDPMessage* copy_target) {
|
||||
fn NetworkMessage* outgoingMessageNonblockingQueuePop(OutgoingMessageQueue* q, NetworkMessage* copy_target) {
|
||||
// immediately returns NULL if there's nothing in the ThreadQueue
|
||||
// copies the ParsedClientCommand into `copy_target` if there is something in the queue
|
||||
// and marks it as popped from the queue
|
||||
UDPMessage* result = NULL;
|
||||
NetworkMessage* result = NULL;
|
||||
|
||||
lockMutex(&q->mutex); {
|
||||
if (q->count > 0) {
|
||||
@@ -80,8 +111,8 @@ fn UDPMessage* outgoingMessageNonblockingQueuePop(OutgoingMessageQueue* q, UDPMe
|
||||
return result;
|
||||
}
|
||||
|
||||
fn UDPMessage* outgoingMessageQueuePop(OutgoingMessageQueue* q, UDPMessage* copy_target) {
|
||||
UDPMessage* result = NULL;
|
||||
fn NetworkMessage* outgoingMessageQueuePop(OutgoingMessageQueue* q, NetworkMessage* copy_target) {
|
||||
NetworkMessage* result = NULL;
|
||||
|
||||
lockMutex(&q->mutex); {
|
||||
while (q->count == 0) {
|
||||
@@ -99,7 +130,6 @@ fn UDPMessage* outgoingMessageQueuePop(OutgoingMessageQueue* q, UDPMessage* copy
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn bool socketAddressEqual(SocketAddress a, SocketAddress b) {
|
||||
return a.sin_addr.s_addr == b.sin_addr.s_addr
|
||||
&& a.sin_port == b.sin_port;
|
||||
@@ -109,6 +139,15 @@ fn bool socketAddressEqual(SocketAddress a, SocketAddress b) {
|
||||
|
||||
// the only real difference between a udp "server" and a "client" is the bind() syscall
|
||||
// that the server makes in order to specify a port/address that it's listening on
|
||||
i32 recv_exact(i32 socket, void* buf, u16 bytes_to_recv) {
|
||||
i32 got, got_this_iter;
|
||||
for (got = 0; got < bytes_to_recv; got += got_this_iter) {
|
||||
got_this_iter = recv(socket, (char*)buf + got, bytes_to_recv - got, 0);
|
||||
if (got_this_iter <= 0) return got_this_iter;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
UDPServer createUDPServer(u16 server_port) {
|
||||
UDPServer result = {0};
|
||||
// define the address we'll be listening on
|
||||
@@ -166,21 +205,247 @@ void infiniteReadUDPServer(UDPServer* server, void (*handleMessage)(u8* udp_mess
|
||||
i32 addrlen = sizeof(struct sockaddr);
|
||||
while (true) {
|
||||
bytes_recieved = recvfrom(server->server_socket, message_buffer, UDP_MAX_MESSAGE_LEN, 0, (struct sockaddr *)&client_address, (socklen_t*)&addrlen);
|
||||
|
||||
//gethostbyaddr: determine who sent the datagram
|
||||
//struct hostent* hostp = gethostbyaddr(
|
||||
// (const char *)&client_address.sin_addr.s_addr,
|
||||
// sizeof(client_address.sin_addr.s_addr),
|
||||
// AF_INET
|
||||
//);
|
||||
|
||||
//ptr printable_host_IP_address_string = inet_ntoa(client_address.sin_addr);
|
||||
|
||||
handleMessage(message_buffer, bytes_recieved, client_address, server->server_socket);
|
||||
MemoryZero(message_buffer, UDP_MAX_MESSAGE_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void* infinitelyServeUDPSocket(void* servable) {
|
||||
ServableUDPInfo info = *(ServableUDPInfo*)servable;
|
||||
infiniteReadUDPServer(&info.server, info.callback);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TCPClient createTCPClient(u16 server_port, str addr) {
|
||||
TCPClient result = {0};
|
||||
// define the address we'll be listening on
|
||||
result.server_address.sin_family = AF_INET;
|
||||
if (addr == 0) {
|
||||
result.server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
} else {
|
||||
result.server_address.sin_addr.s_addr = inet_addr(addr);
|
||||
}
|
||||
result.server_address.sin_port = htons(server_port);
|
||||
|
||||
// get a FileDescriptor number from the OS to use for our socket
|
||||
result.socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (result.socket < 0) {
|
||||
return result;
|
||||
}
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
i32 connect_result = connect(result.socket, (struct sockaddr *)&result.server_address, addr_len);
|
||||
result.ready = connect_result != -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TCPServer createTCPServer(u16 server_port) {
|
||||
TCPServer result = {0};
|
||||
// define the address we'll be listening on
|
||||
result.address.sin_family = AF_INET;
|
||||
result.address.sin_addr.s_addr = inet_addr("0.0.0.0");//htonl(INADDR_ANY);
|
||||
result.address.sin_port = htons(server_port);
|
||||
|
||||
// get a FileDescriptor number from the OS to use for our TCP socket
|
||||
result.socket_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (result.socket_fd < 0) {
|
||||
return result;
|
||||
}
|
||||
// to let us immediately kill and restart server
|
||||
i32 optval = 1;
|
||||
setsockopt(result.socket_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(i32));
|
||||
|
||||
// bind() the TCP
|
||||
result.ready = bind(result.socket_fd, (struct sockaddr *)&result.address, sizeof(result.address)) >= 0;
|
||||
if (result.ready) {
|
||||
result.ready = result.ready && (listen(result.socket_fd, 10) >= 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i32 recvMessage(i32 socket, u8* message_buffer, void (*addSystemMessage)(u8* msg)) {
|
||||
i32 bytes_recieved;
|
||||
u16 msg_len;
|
||||
i32 first_recv_got = recv_exact(socket, &msg_len, 2);
|
||||
if (first_recv_got <= 0) {
|
||||
return first_recv_got;
|
||||
}
|
||||
msg_len = ntohs(msg_len); // parse it to our correct byte order
|
||||
|
||||
bytes_recieved = recv_exact(socket, message_buffer, msg_len);
|
||||
if (addSystemMessage != NULL) {
|
||||
char sbuf[128] = {0};
|
||||
sprintf(sbuf, "bytes_recieved=%d\n", bytes_recieved);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
return bytes_recieved;
|
||||
}
|
||||
|
||||
void infiniteReadTCPServer(
|
||||
TCPServer* server,
|
||||
void (*handleMessage)(u8* udp_message, u32 udp_len, SocketAddress sending_address, i32 socket),
|
||||
void (*closeConnection)(i32 socket_fd),
|
||||
void (*addSystemMessage)(u8* msg)
|
||||
) {
|
||||
u8 message_buffer[UDP_MAX_MESSAGE_LEN] = {0};
|
||||
i32 bytes_recieved = 0;
|
||||
SocketAddress client_address = {0};
|
||||
i32 addrlen = sizeof(struct sockaddr);
|
||||
i32 new_fd;
|
||||
struct pollfd pollable_fds[NET_SERVER_MAX_CLIENTS+1] = {0}; // +1 for the listener socket
|
||||
// poll the `listen()`ed socket_fd
|
||||
pollable_fds[0].fd = server->socket_fd;
|
||||
pollable_fds[0].events = POLLIN;
|
||||
u32 pollable_fd_count = 1;
|
||||
|
||||
i32 poll_event_count;
|
||||
bool should_keep_serving = true;
|
||||
while (should_keep_serving) {
|
||||
poll_event_count = poll(pollable_fds, pollable_fd_count, -1);
|
||||
if (poll_event_count == -1) {
|
||||
// TODO handle error better
|
||||
should_keep_serving = false;
|
||||
continue;
|
||||
}
|
||||
for(u32 i = 0; i < pollable_fd_count; i++) {
|
||||
bool is_fd_readable = pollable_fds[i].revents & (POLLIN | POLLHUP);
|
||||
if (is_fd_readable) {
|
||||
bool is_fd_main_server_listener = pollable_fds[i].fd == server->socket_fd;
|
||||
if (is_fd_main_server_listener) { // it's a new connection
|
||||
new_fd = accept(server->socket_fd, (struct sockaddr *)&client_address, (socklen_t*)&addrlen);
|
||||
if (new_fd == -1) {
|
||||
if (addSystemMessage != NULL) {
|
||||
addSystemMessage((u8*)"TODO: handle this accept() error for real, bitch");
|
||||
}
|
||||
} else {
|
||||
if (pollable_fd_count < NET_SERVER_MAX_CLIENTS+1) {
|
||||
pollable_fds[pollable_fd_count].fd = new_fd;
|
||||
pollable_fds[pollable_fd_count].events = POLLIN | POLLHUP;
|
||||
pollable_fds[pollable_fd_count].revents = 0;
|
||||
pollable_fd_count++;
|
||||
if (addSystemMessage != NULL) {
|
||||
char sbuf[128] = {0};
|
||||
sprintf(sbuf, "new connection on socket=%d, total=%d\n", new_fd, pollable_fd_count);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
} else {
|
||||
send(new_fd, "server full", 11, 0); // go away sir, we are out of space to keep track of this socket
|
||||
close(new_fd);
|
||||
}
|
||||
}
|
||||
} else {// Otherwise we're just a regular client
|
||||
bytes_recieved = recvMessage(pollable_fds[i].fd, message_buffer, addSystemMessage);
|
||||
if (bytes_recieved <= 0) { // error condition
|
||||
bool client_hung_up = bytes_recieved == 0;
|
||||
// TODO do something with the error case
|
||||
closeConnection(pollable_fds[i].fd);
|
||||
close(pollable_fds[i].fd);
|
||||
if (addSystemMessage != NULL) {
|
||||
char sbuf[256] = {0};
|
||||
sprintf(sbuf, "closed connection on socket=%d, client_hung_up? %s\n", pollable_fds[i].fd, client_hung_up ? "yes" : "no");
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
// copy the last one over the current one and "forget" the last one by decrementing the count
|
||||
pollable_fds[i] = pollable_fds[--pollable_fd_count];
|
||||
} else { // we got an actual message from this guy
|
||||
handleMessage(message_buffer, bytes_recieved, client_address, pollable_fds[i].fd);
|
||||
}
|
||||
MemoryZero(message_buffer, UDP_MAX_MESSAGE_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void infiniteReadTCPClient(
|
||||
i32 socket,
|
||||
bool* should_quit,
|
||||
void (*handleMessage)(u8* udp_message, i32 bytes_recieved),
|
||||
void (*addSystemMessage)(u8* msg)
|
||||
) {
|
||||
u8 message_buffer[UDP_MAX_MESSAGE_LEN] = {0};
|
||||
i32 bytes_recieved = 0;
|
||||
while ((*should_quit) != true) {
|
||||
bytes_recieved = recvMessage(socket, message_buffer, addSystemMessage);
|
||||
if (bytes_recieved == -1) {
|
||||
if (addSystemMessage != NULL) {
|
||||
char sbuf[128] = {0};
|
||||
sprintf(sbuf, "TODO handle this error, bytes_recieved=%d\n", bytes_recieved);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
handleMessage(message_buffer, bytes_recieved);
|
||||
MemoryZero(message_buffer, UDP_MAX_MESSAGE_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
MultiServer createMultiServer(u16 server_port) {
|
||||
MultiServer result = {0};
|
||||
// define the address we'll be listening on
|
||||
result.address.sin_family = AF_INET;
|
||||
result.address.sin_addr.s_addr = inet_addr("0.0.0.0");//htonl(INADDR_ANY);
|
||||
result.address.sin_port = htons(server_port);
|
||||
|
||||
// get a FileDescriptor number from the OS to use for our UDP socket
|
||||
result.udp_socket_fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (result.udp_socket_fd < 0) {
|
||||
return result;
|
||||
}
|
||||
// get a FileDescriptor number from the OS to use for our TCP socket
|
||||
result.tcp_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (result.tcp_socket_fd < 0) {
|
||||
return result;
|
||||
}
|
||||
// to let us immediately kill and restart server
|
||||
i32 optval = 1;
|
||||
setsockopt(result.udp_socket_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(i32));
|
||||
setsockopt(result.tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(i32));
|
||||
|
||||
// bind() the UDP
|
||||
result.ready = bind(result.udp_socket_fd, (struct sockaddr *)&result.address, sizeof(result.address)) >= 0;
|
||||
|
||||
// bind() the TCP
|
||||
result.ready = result.ready && (bind(result.tcp_socket_fd, (struct sockaddr *)&result.address, sizeof(result.address)) >= 0);
|
||||
|
||||
if (result.ready) {
|
||||
result.ready = result.ready && (listen(result.tcp_socket_fd, 10) >= 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void infiniteReadMultiServer(MultiServer* server, void (*handleMessage)(u8* udp_message, u32 udp_len, SocketAddress sending_address, i32 socket)) {
|
||||
UDPServer udp_server = {
|
||||
.ready = server->ready,
|
||||
.server_address = server->address,
|
||||
.server_socket = server->udp_socket_fd,
|
||||
};
|
||||
ServableUDPInfo udp_info = {
|
||||
.server = udp_server,
|
||||
.callback = handleMessage,
|
||||
};
|
||||
Thread udp_listener_thread = spawnThread(&infinitelyServeUDPSocket, &udp_info);
|
||||
|
||||
u8 message_buffer[UDP_MAX_MESSAGE_LEN] = {0};
|
||||
SocketAddress client_address = {0};
|
||||
i32 addrlen = sizeof(struct sockaddr);
|
||||
i32 new_fd;
|
||||
i32 bytes_recieved = 0;
|
||||
while (true) {
|
||||
// TCP
|
||||
new_fd = accept(server->tcp_socket_fd, (struct sockaddr *)&client_address, (socklen_t*)&addrlen);
|
||||
bytes_recieved = recv(new_fd, message_buffer, UDP_MAX_MESSAGE_LEN, 0);
|
||||
if (bytes_recieved > 0) {
|
||||
handleMessage(message_buffer, bytes_recieved, client_address, new_fd);
|
||||
}
|
||||
MemoryZero(message_buffer, UDP_MAX_MESSAGE_LEN);
|
||||
}
|
||||
osThreadJoin(udp_listener_thread, MAX_u64);
|
||||
}
|
||||
|
||||
// TODO: sendall() to handle cases when the sendto() bytes return value is less than the intended bytes to send... stupid kernel fuckin wit us.
|
||||
i32 sendUDPu8List(i32 using_socket, SocketAddress* to, u8List* message) {
|
||||
return sendto(
|
||||
@@ -196,3 +461,14 @@ i32 sendUDPu8List(i32 using_socket, SocketAddress* to, u8List* message) {
|
||||
i32 sendUDPMessage(UDPServer* to, u8* message, u32 len) {
|
||||
return sendto(to->server_socket, message, len, 0, (struct sockaddr *)&to->server_address, sizeof(struct sockaddr));
|
||||
}
|
||||
i32 sendTCPMessage(NetworkMessage msg) {
|
||||
assert(msg.use_socket);
|
||||
assert(msg.socket_fd >= 0);
|
||||
u16 msg_len = htons(msg.bytes_len);
|
||||
i32 result = send(msg.socket_fd, &msg_len, 2, 0);
|
||||
if (result == -1) {
|
||||
return result;
|
||||
}
|
||||
return send(msg.socket_fd, msg.bytes, msg.bytes_len, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "../base/all.h"
|
||||
#include "../string_chunk.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define UTF8_MAX_WIDTH 4
|
||||
|
||||
+146
-154
@@ -6,13 +6,13 @@
|
||||
* my_variable
|
||||
* MY_CONSTANT
|
||||
* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/random.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "base/impl.c"
|
||||
#define NET_OUTGOING_MESSAGE_QUEUE_LEN 64
|
||||
#define NET_OUTGOING_MESSAGE_QUEUE_LEN (64)
|
||||
#define NET_SERVER_MAX_CLIENTS (16)
|
||||
#include "lib/network.c"
|
||||
#include "lib/tui.c"
|
||||
#include "string_chunk.c"
|
||||
@@ -21,9 +21,7 @@
|
||||
#define LEFT_ROOM_ENTITES_LEN (KB(1))
|
||||
#define ROOM_MAP_COLLISIONS_LEN MAX_ROOMS/8
|
||||
#define CLIENT_COMMAND_LIST_LEN 8
|
||||
#define SERVER_PORT 7777
|
||||
#define SERVER_MAX_HEAP_MEMORY MB(256)
|
||||
#define SERVER_MAX_CLIENTS 16
|
||||
#define GAME_THREAD_CONCURRENCY 2
|
||||
#define GOAL_NETWORK_SEND_LOOPS_PER_S 8
|
||||
#define GOAL_NETWORK_SEND_LOOP_US 1000000/GOAL_NETWORK_SEND_LOOPS_PER_S
|
||||
@@ -53,6 +51,7 @@ typedef struct ParsedClientCommand {
|
||||
u16 alt_port;
|
||||
u32 sender_ip;
|
||||
u32 alt_ip;
|
||||
i32 socket_fd;
|
||||
u32 qty;
|
||||
CommodityType commodity;
|
||||
StringChunkList name;
|
||||
@@ -80,12 +79,11 @@ typedef struct Account {
|
||||
} Account;
|
||||
|
||||
typedef struct Client {
|
||||
u16 lan_port;
|
||||
i32 lan_ip;
|
||||
bool active;
|
||||
i32 socket_fd;
|
||||
u64 account_id;
|
||||
SocketAddress address;
|
||||
CommandType commands[CLIENT_COMMAND_LIST_LEN];
|
||||
u64 last_ping;
|
||||
} Client;
|
||||
|
||||
typedef struct ClientList {
|
||||
@@ -214,14 +212,16 @@ fn void exitWithErrorMessage(ptr msg) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn u32 pushClient(ClientList* clients, SocketAddress addr) {
|
||||
Client new_client = {0};
|
||||
new_client.last_ping = state.frame;
|
||||
new_client.address = addr;
|
||||
fn u32 pushClient(ClientList* clients, SocketAddress addr, i32 socket_fd) {
|
||||
Client new_client = {
|
||||
.active = true,
|
||||
.socket_fd = socket_fd,
|
||||
.address = addr,
|
||||
};
|
||||
|
||||
// first, try to overwrite an old dc'ed client
|
||||
for (u32 i = 1; i < clients->length; i++) {
|
||||
if (clients->items[i].last_ping == 0) {
|
||||
if (clients->items[i].active == false) {
|
||||
clients->items[i] = new_client;
|
||||
return i;
|
||||
}
|
||||
@@ -248,20 +248,10 @@ fn bool deleteClientByAccountId(ClientList* clients, u64 id) {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
fn u32 findClientHandleByAccountId(ClientList* clients, u64 id) {
|
||||
fn u32 findClientHandle(ClientList* clients, SocketAddress address, i32 socket_fd) {
|
||||
for (u32 i = 0; i < clients->length; i++) {
|
||||
Client c = clients->items[i];
|
||||
if (c.account_id == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn u32 findClientHandleBySocketAddress(ClientList* clients, SocketAddress address) {
|
||||
for (u32 i = 0; i < clients->length; i++) {
|
||||
Client c = clients->items[i];
|
||||
if (socketAddressEqual(address, c.address)) {
|
||||
if (socketAddressEqual(address, c.address) && socket_fd == c.socket_fd) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -295,8 +285,8 @@ fn bool shipIsNull(PlayerShip* ship) {
|
||||
return ship->id == 0 && ship->base_cost == 0;
|
||||
}
|
||||
|
||||
fn UDPMessage makeMessageSystemPassengers(StarSystem* sys) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
fn NetworkMessage makeMessageSystemPassengers(StarSystem* sys) {
|
||||
NetworkMessage outgoing_message = { .use_socket = true };
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessageSystemPassengers;
|
||||
outgoing_message.bytes[msg_i++] = (u8)sys->idx;
|
||||
@@ -312,8 +302,8 @@ fn UDPMessage makeMessageSystemPassengers(StarSystem* sys) {
|
||||
return outgoing_message;
|
||||
}
|
||||
|
||||
fn UDPMessage makeMessageSystemCommodities(StarSystem* sys) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
fn NetworkMessage makeMessageSystemCommodities(StarSystem* sys) {
|
||||
NetworkMessage outgoing_message = { .use_socket = true };
|
||||
u32 planet_count = starSystemPlanetCount(sys);
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessageSystemCommodities;
|
||||
@@ -328,8 +318,8 @@ fn UDPMessage makeMessageSystemCommodities(StarSystem* sys) {
|
||||
return outgoing_message;
|
||||
}
|
||||
|
||||
fn void sendMessageTransactionResult(SocketAddress addr, u32 qty, bool buying, u32 credits) {
|
||||
UDPMessage outgoing_message = {.address = addr};
|
||||
fn void sendMessageTransactionResult(i32 socket_fd, SocketAddress addr, u32 qty, bool buying, u32 credits) {
|
||||
NetworkMessage outgoing_message = { .address = addr, .use_socket = true, .socket_fd = socket_fd };
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessageTransactionResult;
|
||||
outgoing_message.bytes[msg_i++] = buying;
|
||||
@@ -340,8 +330,8 @@ fn void sendMessageTransactionResult(SocketAddress addr, u32 qty, bool buying, u
|
||||
addSystemMessage((u8*)"Message TransactionResult sent");
|
||||
}
|
||||
|
||||
fn UDPMessage makeMessagePlayerDetails(PlayerShip ship) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
fn NetworkMessage makeMessagePlayerDetails(PlayerShip ship) {
|
||||
NetworkMessage outgoing_message = {0};
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessagePlayerDetails;
|
||||
outgoing_message.bytes[msg_i++] = ship.type;
|
||||
@@ -373,9 +363,8 @@ fn UDPMessage makeMessagePlayerDetails(PlayerShip ship) {
|
||||
return outgoing_message;
|
||||
}
|
||||
|
||||
fn void sendMessageJobAcceptResult(SocketAddress addr, bool result) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
outgoing_message.address = addr;
|
||||
fn void sendMessageJobAcceptResult(i32 socket_fd, SocketAddress addr, bool result) {
|
||||
NetworkMessage outgoing_message = { .address = addr, .use_socket = true, .socket_fd = socket_fd };
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessageJobAcceptResult;
|
||||
outgoing_message.bytes[msg_i++] = result;
|
||||
@@ -384,9 +373,8 @@ fn void sendMessageJobAcceptResult(SocketAddress addr, bool result) {
|
||||
addSystemMessage((u8*)"MessageJobAcceptResult sent");
|
||||
}
|
||||
|
||||
fn void sendMessagePayoffResult(SocketAddress addr) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
outgoing_message.address = addr;
|
||||
fn void sendMessagePayoffResult(i32 socket_fd, SocketAddress addr) {
|
||||
NetworkMessage outgoing_message = { .address = addr, .use_socket = true, .socket_fd = socket_fd };
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessagePayoffResult;
|
||||
outgoing_message.bytes_len = msg_i;
|
||||
@@ -394,9 +382,8 @@ fn void sendMessagePayoffResult(SocketAddress addr) {
|
||||
addSystemMessage((u8*)"MessagePayoffResult sent");
|
||||
}
|
||||
|
||||
fn void sendMessageStarPositions(SocketAddress addr) {
|
||||
UDPMessage outgoing_message = {0};
|
||||
outgoing_message.address = addr;
|
||||
fn void sendMessageStarPositions(i32 socket_fd, SocketAddress addr) {
|
||||
NetworkMessage outgoing_message = { .use_socket = true, .address = addr, .socket_fd = socket_fd };
|
||||
// tell the client about the map
|
||||
u32 star_msg_size = 2+MAX_PLANETS;
|
||||
outgoing_message.bytes_len = 1+(star_msg_size*STAR_SYSTEM_COUNT);
|
||||
@@ -409,18 +396,24 @@ fn void sendMessageStarPositions(SocketAddress addr) {
|
||||
}
|
||||
}
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessageStarPositions sent");
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "MessageStarPositions sent socket=%d, message_len=%d", socket_fd, outgoing_message.bytes_len);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
|
||||
fn void sendMessagePlayerDetails(PlayerShip ship, SocketAddress addr) {
|
||||
UDPMessage outgoing_message = makeMessagePlayerDetails(ship);
|
||||
fn void sendMessagePlayerDetails(i32 socket_fd, PlayerShip ship, SocketAddress addr) {
|
||||
NetworkMessage outgoing_message = makeMessagePlayerDetails(ship);
|
||||
outgoing_message.address = addr;
|
||||
outgoing_message.use_socket = true;
|
||||
outgoing_message.socket_fd = socket_fd;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessagePlayerDetails sent");
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "MessagePlayerDetails sent socket=%d, message_len=%d", socket_fd, outgoing_message.bytes_len);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
|
||||
fn void sendMessageAuctionBidResult(SocketAddress addr, AuctionBidResult result) {
|
||||
UDPMessage outgoing_message = {.address = addr};
|
||||
fn void sendMessageAuctionBidResult(i32 socket_fd, SocketAddress addr, AuctionBidResult result) {
|
||||
NetworkMessage outgoing_message = { .address = addr, .use_socket = true, .socket_fd = socket_fd };
|
||||
u32 msg_i = 0;
|
||||
outgoing_message.bytes[msg_i++] = (u8)MessageAuctionBidResult;
|
||||
outgoing_message.bytes[msg_i++] = result;
|
||||
@@ -430,11 +423,13 @@ fn void sendMessageAuctionBidResult(SocketAddress addr, AuctionBidResult result)
|
||||
}
|
||||
|
||||
fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) {
|
||||
dbg("%d: %s from %s:%d\n", len, command_type_strings[message[0]], inet_ntoa(sender.sin_addr), sender.sin_port);
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "%d: %s from %s:%d\n", len, command_type_strings[message[0]], inet_ntoa(sender.sin_addr), sender.sin_port);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
u32 msg_idx = 0;
|
||||
ParsedClientCommand parsed = {
|
||||
.type = (CommandType)message[msg_idx++],
|
||||
.socket_fd = socket,
|
||||
.sender_ip = sender.sin_addr.s_addr,
|
||||
.sender_port = sender.sin_port,
|
||||
};
|
||||
@@ -482,7 +477,6 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
|
||||
sprintf(sbuf, "Logging in player: %s %d %s\n", command_type_strings[parsed.type], name_len, message + 7);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
} break;
|
||||
case CommandKeepAlive: break;
|
||||
case CommandPayMortgage: {
|
||||
parsed.id = readU64FromBufferLE(message + msg_idx);
|
||||
MemoryZero(sbuf, SBUFLEN);
|
||||
@@ -521,18 +515,30 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
|
||||
pccThreadSafeQueuePush(state.network_recv_queue, &parsed);
|
||||
}
|
||||
|
||||
fn void* receiveNetworkUpdates(void* udp) {
|
||||
UDPServer server = *(UDPServer*)udp;
|
||||
dbg("receiveNetworkUpdates() sock=%d\n", server.server_socket);
|
||||
infiniteReadUDPServer(&server, handleIncomingMessage);
|
||||
fn void removeClientBySocketFd(i32 socket_fd) {
|
||||
Client blank_client = {0};
|
||||
// i=1 because first client is null-client
|
||||
for (u32 i = 1; i < state.clients.length; i++) {
|
||||
if (state.clients.items[i].socket_fd == socket_fd) {
|
||||
state.clients.items[i] = blank_client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void* receiveNetworkUpdates(void* tcp_server) {
|
||||
TCPServer server = *(TCPServer*)tcp_server;
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "receiveNetworkUpdates() sock=%d\n", server.socket_fd);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
infiniteReadTCPServer(&server, handleIncomingMessage, removeClientBySocketFd, addSystemMessage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void* sendNetworkUpdates(void* sock) {
|
||||
fn void* sendNetworkUpdates(void* tcp_server) {
|
||||
TCPServer server = *(TCPServer*)tcp_server;
|
||||
ThreadContext tctx = {0};
|
||||
tctxInit(&tctx);
|
||||
i32* socket_ptr = (i32*)sock;
|
||||
i32 socket = *socket_ptr;
|
||||
i32 socket = server.socket_fd;
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
u64 send_loop = 0;
|
||||
while (!should_quit) {
|
||||
@@ -541,103 +547,96 @@ fn void* sendNetworkUpdates(void* sock) {
|
||||
|
||||
// 1. clear out our "outgoingMessage" queue
|
||||
{
|
||||
UDPMessage to_send = { 0 };
|
||||
UDPMessage* next_to_send = outgoingMessageNonblockingQueuePop(state.network_send_queue, &to_send);
|
||||
NetworkMessage to_send = { 0 };
|
||||
NetworkMessage* next_to_send = outgoingMessageNonblockingQueuePop(state.network_send_queue, &to_send);
|
||||
u8List bytes_list = { 0 };
|
||||
while (next_to_send != NULL) {
|
||||
if (to_send.use_socket) {
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "sendTCPMessage() sock=%d msg=%s len=%d\n", to_send.socket_fd, MESSAGE_STRINGS[to_send.bytes[0]], to_send.bytes_len);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
sendTCPMessage(to_send);
|
||||
} else { // UDP
|
||||
bytes_list.items = to_send.bytes;
|
||||
bytes_list.length = to_send.bytes_len;
|
||||
bytes_list.capacity = to_send.bytes_len;
|
||||
sendUDPu8List(socket, &to_send.address, &bytes_list);
|
||||
}
|
||||
next_to_send = outgoingMessageNonblockingQueuePop(state.network_send_queue, &to_send);
|
||||
}
|
||||
}
|
||||
|
||||
UDPMessage sys_udp_msg = { 0 };
|
||||
sys_udp_msg = makeMessageSystemCommodities(&state.map[send_loop/2 % STAR_SYSTEM_COUNT]);
|
||||
u8List sys_msg = {
|
||||
.capacity = UDP_MAX_MESSAGE_LEN,
|
||||
.items = sys_udp_msg.bytes,
|
||||
.length = sys_udp_msg.bytes_len,
|
||||
};
|
||||
UDPMessage sys_pass_udp_msg = { 0 };
|
||||
sys_pass_udp_msg = makeMessageSystemPassengers(&state.map[send_loop/2 % STAR_SYSTEM_COUNT]);
|
||||
u8List sys_pass_msg = {
|
||||
.capacity = UDP_MAX_MESSAGE_LEN,
|
||||
.items = sys_pass_udp_msg.bytes,
|
||||
.length = sys_pass_udp_msg.bytes_len,
|
||||
};
|
||||
NetworkMessage base_sys_msg = makeMessageSystemCommodities(&state.map[send_loop/2 % STAR_SYSTEM_COUNT]);
|
||||
NetworkMessage base_pass_msg = makeMessageSystemPassengers(&state.map[send_loop/2 % STAR_SYSTEM_COUNT]);
|
||||
|
||||
lockMutex(&state.client_mutex); {
|
||||
// WARNING the `i` starts at 1 here because state.clients.items[0] is a "null" Client
|
||||
for (u32 i = 1; i < state.clients.length; i++) {
|
||||
Client client = state.clients.items[i];
|
||||
if (client.last_ping+CLIENT_TIMEOUT_FRAMES < state.frame) {
|
||||
memset(&state.clients.items[i], 0, sizeof(Client));
|
||||
if (client.active == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (send_loop % 2 == 0) {
|
||||
// every other "send-frame" we send each connnected client the current prices for a different system
|
||||
// so that the prices mostly stay up to date pretty quickly without having to track changes
|
||||
sendUDPu8List(socket, &client.address, &sys_msg);
|
||||
base_sys_msg.socket_fd = client.socket_fd;
|
||||
sendTCPMessage(base_sys_msg);
|
||||
// and the passenger offers
|
||||
sendUDPu8List(socket, &client.address, &sys_pass_msg);
|
||||
base_pass_msg.socket_fd = client.socket_fd;
|
||||
sendTCPMessage(base_pass_msg);
|
||||
|
||||
// send the client the current auction details for their current system
|
||||
Account* account = &state.accounts[client.account_id];
|
||||
if (!accountIsEmpty(account)) {
|
||||
StarSystem curr = state.map[account->ship.system_idx];
|
||||
MemoryZero(sbuf, SBUFLEN);
|
||||
u32 msgidx = 0;
|
||||
sbuf[msgidx++] = MessageAuctionDetails;
|
||||
sbuf[msgidx++] = curr.auction.type;
|
||||
sbuf[msgidx++] = curr.auction.qty;
|
||||
msgidx += writeU32ToBufferLE((u8*)sbuf + msgidx, curr.auction.price);
|
||||
msgidx += writeU32ToBufferLE((u8*)sbuf + msgidx, curr.auction.started_at);
|
||||
msgidx += writeU32ToBufferLE((u8*)sbuf + msgidx, curr.auction.finished_at);
|
||||
u8List msg = {
|
||||
.capacity = UDP_MAX_MESSAGE_LEN,
|
||||
.items = (u8*)sbuf,
|
||||
.length = msgidx,
|
||||
NetworkMessage auction_msg = {
|
||||
.use_socket = true,
|
||||
.socket_fd = client.socket_fd,
|
||||
.address = client.address,
|
||||
};
|
||||
sendUDPu8List(socket, &client.address, &msg);
|
||||
u32 msgidx = 0;
|
||||
auction_msg.bytes[msgidx++] = MessageAuctionDetails;
|
||||
auction_msg.bytes[msgidx++] = curr.auction.type;
|
||||
auction_msg.bytes[msgidx++] = curr.auction.qty;
|
||||
msgidx += writeU32ToBufferLE((u8*)auction_msg.bytes + msgidx, curr.auction.price);
|
||||
msgidx += writeU32ToBufferLE((u8*)auction_msg.bytes + msgidx, curr.auction.started_at);
|
||||
msgidx += writeU32ToBufferLE((u8*)auction_msg.bytes + msgidx, curr.auction.finished_at);
|
||||
auction_msg.bytes_len = msgidx;
|
||||
sendTCPMessage(auction_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// update all the changed systems
|
||||
UDPMessage msg_data;
|
||||
NetworkMessage msg_data;
|
||||
for (u32 ii = 0; ii < STAR_SYSTEM_COUNT; ii++) {
|
||||
if (state.map[ii].changed == true) {
|
||||
// send commodities
|
||||
msg_data = makeMessageSystemCommodities(&state.map[ii]);
|
||||
u8List msg = {
|
||||
.capacity = UDP_MAX_MESSAGE_LEN,
|
||||
.items = msg_data.bytes,
|
||||
.length = msg_data.bytes_len,
|
||||
};
|
||||
sendUDPu8List(socket, &client.address, &msg);
|
||||
msg_data.address = client.address;
|
||||
msg_data.socket_fd = client.socket_fd;
|
||||
msg_data.use_socket = true;
|
||||
sendTCPMessage(msg_data);
|
||||
|
||||
// send passenger jobs
|
||||
MemoryZero(sbuf, SBUFLEN);
|
||||
sprintf(sbuf, "sending passenger jobs for %s\n", STAR_NAMES[ii]);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
msg_data = makeMessageSystemPassengers(&state.map[ii]);
|
||||
msg.capacity = UDP_MAX_MESSAGE_LEN;
|
||||
msg.items = msg_data.bytes;
|
||||
msg.length = msg_data.bytes_len;
|
||||
sendUDPu8List(socket, &client.address, &msg);
|
||||
msg_data.address = client.address;
|
||||
msg_data.socket_fd = client.socket_fd;
|
||||
msg_data.use_socket = true;
|
||||
sendTCPMessage(msg_data);
|
||||
}
|
||||
}
|
||||
// update all the changed accounts
|
||||
for (u32 ii = 0; ii < ACCOUNT_LEN; ii++) {
|
||||
if (state.accounts[ii].changed == true) {
|
||||
msg_data = makeMessagePlayerDetails(state.accounts[ii].ship);
|
||||
u8List msg = {
|
||||
.capacity = UDP_MAX_MESSAGE_LEN,
|
||||
.items = msg_data.bytes,
|
||||
.length = msg_data.bytes_len,
|
||||
};
|
||||
sendUDPu8List(socket, &client.address, &msg);
|
||||
msg_data.address = client.address;
|
||||
msg_data.socket_fd = client.socket_fd;
|
||||
msg_data.use_socket = true;
|
||||
sendTCPMessage(msg_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,7 +669,7 @@ fn void* gameLoop(void* params) {
|
||||
char sbuf[SBUFLEN] = {0};
|
||||
sprintf(sbuf, "Lane %lld (%lld) of %lld starting.", lane_ctx->lane_idx, LaneIdx(), lane_ctx->lane_count);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
UDPMessage outgoing_message = {0};
|
||||
NetworkMessage outgoing_message = { .use_socket = true };
|
||||
u64 loop_start;
|
||||
u64 last_burn = 0;
|
||||
u64 last_hp_regen = 0;
|
||||
@@ -698,7 +697,7 @@ fn void* gameLoop(void* params) {
|
||||
sender.sin_addr.s_addr = msg.sender_ip;
|
||||
sender.sin_port = msg.sender_port;
|
||||
// find which client it is
|
||||
u32 client_handle = findClientHandleBySocketAddress(&state.clients, sender);
|
||||
u32 client_handle = findClientHandle(&state.clients, sender, msg.socket_fd);
|
||||
Client* client = &state.clients.items[client_handle];
|
||||
switch (msg.type) {
|
||||
case CommandBuyAuction: {
|
||||
@@ -713,15 +712,15 @@ fn void* gameLoop(void* params) {
|
||||
player_sys->auction.finished_at = state.frame;
|
||||
account->ship.credits -= player_sys->auction.price;
|
||||
account->ship.commodities[player_sys->auction.type] += player_sys->auction.qty;
|
||||
sendMessageAuctionBidResult(sender, AuctionBidResultPurchased);
|
||||
sendMessagePlayerDetails(account->ship, sender);
|
||||
sendMessageAuctionBidResult(msg.socket_fd, sender, AuctionBidResultPurchased);
|
||||
sendMessagePlayerDetails(msg.socket_fd, account->ship, sender);
|
||||
} else if (!player_has_money_for_purchase) {
|
||||
sendMessageAuctionBidResult(sender, AuctionBidResultNotEnoughMoney);
|
||||
sendMessageAuctionBidResult(msg.socket_fd, sender, AuctionBidResultNotEnoughMoney);
|
||||
} else {
|
||||
sendMessageAuctionBidResult(sender, AuctionBidResultNotEnoughCargoSpace);
|
||||
sendMessageAuctionBidResult(msg.socket_fd, sender, AuctionBidResultNotEnoughCargoSpace);
|
||||
}
|
||||
} else {
|
||||
sendMessageAuctionBidResult(sender, AuctionBidResultAuctionAlreadyFinished);
|
||||
sendMessageAuctionBidResult(msg.socket_fd, sender, AuctionBidResultAuctionAlreadyFinished);
|
||||
}
|
||||
} break;
|
||||
case CommandAcceptPassengerJob: {
|
||||
@@ -751,7 +750,7 @@ fn void* gameLoop(void* params) {
|
||||
MemoryZero(&player_sys->offers[i], sizeof(PassengerJobOffer));
|
||||
player_sys->changed = true;
|
||||
succeeded = true;
|
||||
sendMessageJobAcceptResult(sender, succeeded);
|
||||
sendMessageJobAcceptResult(client->socket_fd, sender, succeeded);
|
||||
// end both for loops "break break;"
|
||||
ii = MAX_PASSENGER_BERTHS;
|
||||
i = MAX_PASSENGER_JOB_OFFERS;
|
||||
@@ -762,7 +761,7 @@ fn void* gameLoop(void* params) {
|
||||
}
|
||||
}
|
||||
if (!succeeded) {
|
||||
sendMessageJobAcceptResult(sender, succeeded);
|
||||
sendMessageJobAcceptResult(client->socket_fd, sender, succeeded);
|
||||
}
|
||||
} break;
|
||||
case CommandPayMortgage: {
|
||||
@@ -778,7 +777,7 @@ fn void* gameLoop(void* params) {
|
||||
account->ship.credits -= amount_to_pay;
|
||||
account->ship.remaining_mortgage -= amount_to_pay;
|
||||
account->changed = true;
|
||||
sendMessagePayoffResult(sender);
|
||||
sendMessagePayoffResult(client->socket_fd, sender);
|
||||
} break;
|
||||
case CommandSetDestination: {
|
||||
if (client_handle == 0) break;
|
||||
@@ -789,7 +788,7 @@ fn void* gameLoop(void* params) {
|
||||
if (client_handle == 0) break;
|
||||
Account* account = &state.accounts[client->account_id];
|
||||
account->ship.ready_to_depart = msg.byte;
|
||||
sendMessagePlayerDetails(account->ship, sender);
|
||||
sendMessagePlayerDetails(client->socket_fd, account->ship, sender);
|
||||
state.all_accounts_ready = true;
|
||||
for (u32 i = 0; i < ACCOUNT_LEN; i++) {
|
||||
if (!accountIsEmpty(&state.accounts[i])) {
|
||||
@@ -853,33 +852,17 @@ fn void* gameLoop(void* params) {
|
||||
}
|
||||
}
|
||||
sys->changed = true;
|
||||
sendMessagePlayerDetails(account->ship, sender);
|
||||
sendMessageTransactionResult(sender, qty_traded, is_buying_from_system, credit_value);
|
||||
} break;
|
||||
case CommandKeepAlive: {
|
||||
//MemoryZero(sbuf, SBUFLEN);
|
||||
//sprintf(sbuf, "KeepAlive for client_handle=%d on frame %lld", client_handle, state.frame);
|
||||
//addSystemMessage((u8*)sbuf);
|
||||
if (client_handle == 0) {
|
||||
outgoing_message.bytes[0] = (u8)MessageNotAlive;
|
||||
outgoing_message.bytes_len = 1;
|
||||
outgoing_message.address = sender;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
} else {
|
||||
state.clients.items[client_handle].last_ping = state.frame;
|
||||
}
|
||||
sendMessagePlayerDetails(client->socket_fd, account->ship, sender);
|
||||
sendMessageTransactionResult(client->socket_fd, sender, qty_traded, is_buying_from_system, credit_value);
|
||||
} break;
|
||||
case CommandLogin: {
|
||||
if (client_handle == 0) {
|
||||
client_handle = pushClient(&state.clients, sender);
|
||||
client_handle = pushClient(&state.clients, sender, msg.socket_fd);
|
||||
client = &state.clients.items[client_handle];
|
||||
MemoryZero(sbuf, SBUFLEN);
|
||||
sprintf(sbuf, "pushed new client handle = %d\n", client_handle);
|
||||
addSystemMessage((u8*)sbuf);
|
||||
}
|
||||
// update/set the lan_ip/port info for p2p connections
|
||||
client->lan_ip = htonl(msg.alt_ip);
|
||||
client->lan_port = htons(msg.alt_port);
|
||||
|
||||
/*
|
||||
struct in_addr ipaddr;
|
||||
@@ -906,12 +889,13 @@ fn void* gameLoop(void* params) {
|
||||
if (pw_matches) {
|
||||
addSystemMessage((u8*)" pw matched\n");
|
||||
existing_account->changed = true;
|
||||
sendMessageStarPositions(sender);
|
||||
sendMessageStarPositions(client->socket_fd, sender);
|
||||
} else {
|
||||
// tell the client they did a bad pw
|
||||
outgoing_message.bytes[0] = (u8)MessageBadPw;
|
||||
outgoing_message.bytes_len = 1;
|
||||
outgoing_message.address = sender;
|
||||
outgoing_message.socket_fd = client->socket_fd;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessageBadPw sent\n");
|
||||
break;
|
||||
@@ -937,6 +921,7 @@ fn void* gameLoop(void* params) {
|
||||
writeU64ToBufferLE(outgoing_message.bytes + 1, existing_account->ship.id);
|
||||
outgoing_message.bytes_len = 9;
|
||||
outgoing_message.address = sender;
|
||||
outgoing_message.socket_fd = client->socket_fd;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessageCharacterId sent\n");
|
||||
} else {
|
||||
@@ -944,6 +929,7 @@ fn void* gameLoop(void* params) {
|
||||
outgoing_message.bytes[0] = (u8)MessageNewAccountCreated;
|
||||
outgoing_message.bytes_len = 1;
|
||||
outgoing_message.address = sender;
|
||||
outgoing_message.socket_fd = client->socket_fd;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessageNewAccountCreated sent\n");
|
||||
}
|
||||
@@ -971,7 +957,7 @@ fn void* gameLoop(void* params) {
|
||||
.base_cost = template.base_cost,
|
||||
.remaining_mortgage = template.base_cost - STARTING_DOWN_PAYMENT,
|
||||
.interest_rate = calcInterestRate(template.base_cost, STARTING_DOWN_PAYMENT),
|
||||
.credits = 20000.0,
|
||||
.credits = 2000.0,
|
||||
.cu_m_fuel = template.cu_m_fuel,
|
||||
.cu_m_o2 = template.cu_m_o2,
|
||||
.id = account->id,
|
||||
@@ -990,18 +976,20 @@ fn void* gameLoop(void* params) {
|
||||
|
||||
// tell the client their account id
|
||||
outgoing_message.address = sender;
|
||||
outgoing_message.socket_fd = client->socket_fd;
|
||||
outgoing_message.bytes_len = 9;
|
||||
outgoing_message.bytes[0] = (u8)MessageCharacterId;
|
||||
writeU64ToBufferLE(outgoing_message.bytes + 1, account->ship.id);
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
addSystemMessage((u8*)"MessageCharacterId sent\n");
|
||||
|
||||
sendMessagePlayerDetails(account->ship, sender);
|
||||
sendMessagePlayerDetails(client->socket_fd, account->ship, sender);
|
||||
|
||||
sendMessageStarPositions(sender);
|
||||
sendMessageStarPositions(client->socket_fd, sender);
|
||||
|
||||
outgoing_message = makeMessageSystemCommodities(&starting_system);
|
||||
outgoing_message.address = sender;
|
||||
outgoing_message.socket_fd = client->socket_fd;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
MemoryZero(sbuf, SBUFLEN);
|
||||
sprintf(sbuf, "%s sent\n", MESSAGE_STRINGS[outgoing_message.bytes[0]]);
|
||||
@@ -1020,9 +1008,10 @@ fn void* gameLoop(void* params) {
|
||||
}
|
||||
|
||||
if (state.all_accounts_ready) {
|
||||
for (u32 i = 1; i < SERVER_MAX_CLIENTS; i++) {
|
||||
if (state.clients.items[i].last_ping != 0) {
|
||||
for (u32 i = 1; i < NET_SERVER_MAX_CLIENTS; i++) {
|
||||
if (state.clients.items[i].active) {
|
||||
outgoing_message.address = state.clients.items[i].address;
|
||||
outgoing_message.socket_fd = state.clients.items[i].socket_fd;
|
||||
outgoing_message.bytes_len = 1;
|
||||
outgoing_message.bytes[0] = (u8)MessageTurnTick;
|
||||
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
|
||||
@@ -1031,9 +1020,10 @@ fn void* gameLoop(void* params) {
|
||||
}
|
||||
|
||||
if (state.someone_won) {
|
||||
for (u32 i = 1; i < SERVER_MAX_CLIENTS; i++) {
|
||||
if (state.clients.items[i].last_ping != 0) {
|
||||
for (u32 i = 1; i < NET_SERVER_MAX_CLIENTS; i++) {
|
||||
if (state.clients.items[i].active) {
|
||||
outgoing_message.address = state.clients.items[i].address;
|
||||
outgoing_message.socket_fd = state.clients.items[i].socket_fd;
|
||||
outgoing_message.bytes_len = 2;
|
||||
outgoing_message.bytes[0] = (u8)MessageGameOver;
|
||||
outgoing_message.bytes[1] = state.winner_id;
|
||||
@@ -1074,7 +1064,7 @@ fn void* gameLoop(void* params) {
|
||||
f32 t_sec = ((f32)state.frame - (f32)grace_period_ends_at) / (f32)GOAL_GAME_LOOPS_PER_S;
|
||||
// t is in minutes
|
||||
f32 t = t_sec / 60;
|
||||
f32 decay = -0.60 * t;
|
||||
f32 decay = -0.65 * t;
|
||||
f32 floor_price = COMMODITIES[sys->auction.type].price * 0.9;
|
||||
sys->auction.price = Max((initial_price * pow(EULERS_E, decay)), floor_price);
|
||||
}
|
||||
@@ -1179,8 +1169,9 @@ fn void* gameLoop(void* params) {
|
||||
addSystemMessage((u8*)sbuf);
|
||||
// send a job completion message?
|
||||
for (u32 i = 1; i < state.clients.length; i++) {
|
||||
if (state.clients.items[i].last_ping != 0 && state.clients.items[i].account_id == acct->id) {
|
||||
if (state.clients.items[i].active && state.clients.items[i].account_id == acct->id) {
|
||||
outgoing_message.address = state.clients.items[i].address;
|
||||
outgoing_message.socket_fd = state.clients.items[i].socket_fd;
|
||||
outgoing_message.bytes_len = 2;
|
||||
outgoing_message.bytes[0] = (u8)MessageJobComplete;
|
||||
outgoing_message.bytes[1] = true;
|
||||
@@ -1201,8 +1192,9 @@ fn void* gameLoop(void* params) {
|
||||
addSystemMessage((u8*)sbuf);
|
||||
// send a job failed message?
|
||||
for (u32 i = 1; i < state.clients.length; i++) {
|
||||
if (state.clients.items[i].last_ping != 0 && state.clients.items[i].account_id == acct->id) {
|
||||
if (state.clients.items[i].active && state.clients.items[i].account_id == acct->id) {
|
||||
outgoing_message.address = state.clients.items[i].address;
|
||||
outgoing_message.socket_fd = state.clients.items[i].socket_fd;
|
||||
outgoing_message.bytes_len = 2;
|
||||
outgoing_message.bytes[0] = (u8)MessageJobComplete;
|
||||
outgoing_message.bytes[1] = false;
|
||||
@@ -1456,9 +1448,9 @@ i32 main(i32 argc, ptr argv[]) {
|
||||
state.network_send_queue = newOutgoingMessageQueue(&permanent_arena);
|
||||
// alloc the global hashmap of rooms
|
||||
// init + alloc clients
|
||||
state.clients.capacity = SERVER_MAX_CLIENTS;
|
||||
state.clients.capacity = NET_SERVER_MAX_CLIENTS;
|
||||
state.clients.length = 1; // making entry 0 to be a "null" client
|
||||
state.clients.items = (Client*)arenaAllocArray(&permanent_arena, Client, SERVER_MAX_CLIENTS);
|
||||
state.clients.items = (Client*)arenaAllocArray(&permanent_arena, Client, NET_SERVER_MAX_CLIENTS);
|
||||
for (i32 i = 0; i < SYSTEM_MESSAGES_LEN; i++) {
|
||||
system_messages[i].capacity = MAX_SYSTEM_MESSAGE_LEN;
|
||||
system_messages[i].length = 0;
|
||||
@@ -1657,13 +1649,13 @@ i32 main(i32 argc, ptr argv[]) {
|
||||
}
|
||||
|
||||
// 2. spin off sendNetworkUpdates() infinite loop thread
|
||||
UDPServer listener = createUDPServer(SERVER_PORT);
|
||||
if (!listener.ready) {
|
||||
exitWithErrorMessage("Couldn't start the udp server");
|
||||
TCPServer server = createTCPServer(SERVER_PORT);
|
||||
if (!server.ready) {
|
||||
exitWithErrorMessage("Couldn't start the server");
|
||||
}
|
||||
Thread send_thread = spawnThread(&sendNetworkUpdates, &listener.server_socket);
|
||||
Thread send_thread = spawnThread(&sendNetworkUpdates, &server);
|
||||
// 3. infinitely wait for incoming UDP messages and process them (usually by just dropping user-commands into the relevant block of shared memory)
|
||||
Thread recv_thread = spawnThread(&receiveNetworkUpdates, &listener);
|
||||
Thread recv_thread = spawnThread(&receiveNetworkUpdates, &server);
|
||||
|
||||
u64 lane_broadcast_val = 0;
|
||||
Barrier barrier = osBarrierAlloc(GAME_THREAD_CONCURRENCY);
|
||||
|
||||
+1
-2
@@ -18,6 +18,7 @@
|
||||
#define AUCTION_COMMODITY_CUTOFF (7)
|
||||
#define MAX_SCREEN_HEIGHT 300
|
||||
#define MAX_SCREEN_WIDTH 800
|
||||
#define SERVER_PORT 7777
|
||||
|
||||
#define AUCTION_PRICE_START_MULTIPLE (12)
|
||||
|
||||
@@ -366,7 +367,6 @@ typedef enum Direction {
|
||||
|
||||
typedef enum CommandType {
|
||||
CommandInvalid,
|
||||
CommandKeepAlive,
|
||||
CommandLogin,
|
||||
CommandCreateCharacter,
|
||||
CommandTransact,
|
||||
@@ -380,7 +380,6 @@ typedef enum CommandType {
|
||||
|
||||
static const char* command_type_strings[CommandType_Count] = {
|
||||
"Invalid",
|
||||
"KeepAlive",
|
||||
"Login",
|
||||
"CreateCharacter",
|
||||
"ReadyStatus",
|
||||
|
||||
Reference in New Issue
Block a user