diff --git a/.gitmodules b/.gitmodules index 69b0692..5d1c17e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "thirdparty/enet"] path = thirdparty/enet url = https://github.com/lsalzman/enet.git +[submodule "thirdparty/Chipmunk2D"] + path = thirdparty/Chipmunk2D + url = https://github.com/slembcke/Chipmunk2D.git diff --git a/.vscode/settings.json b/.vscode/settings.json index fc2cb77..bcaafff 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,6 +31,11 @@ "types.h": "c", "cmath": "c", "math.h": "c", - "corecrt_math.h": "c" + "corecrt_math.h": "c", + "cppolyline.h": "c", + "chipmunk_private.h": "c", + "chipmunk.h": "c", + "cpbody.h": "c", + "chipmunk_structs.h": "c" } } \ No newline at end of file diff --git a/build_debug.bat b/build_debug.bat index a7fd93a..13f8efb 100644 --- a/build_debug.bat +++ b/build_debug.bat @@ -1,11 +1,20 @@ @echo off -@REM what all the flags mean: https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 +@REM what all the compile flags mean: https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 WHERE sokol-shdc.exe IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/floooh/sokol-tools-bin/blob/master/bin/win32/sokol-shdc.exe and put it in this folder @REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos -cl /MP /Zi /Fd"flight.pdb" /I"thirdparty" /Fe"flight" /I"thirdparty\enet\include" main.c gamestate.c server.c debugdraw.c^ - thirdparty\enet\callbacks.c thirdparty\enet\compress.c thirdparty\enet\host.c thirdparty\enet\list.c thirdparty\enet\packet.c thirdparty\enet\peer.c thirdparty\enet\protocol.c thirdparty\enet\win32.c Ws2_32.lib winmm.lib \ No newline at end of file +setlocal enabledelayedexpansion enableextensions +pushd thirdparty\Chipmunk2D\src + set MUNKSRC= + for %%x in (*.c) do set MUNKSRC=!MUNKSRC! thirdparty\Chipmunk2D\src\%%x +popd + +cl /MP /Zi /Fd"flight.pdb" /Fe"flight"^ + /I"thirdparty" /I"thirdparty\enet\include" /I"thirdparty\Chipmunk2D\include\chipmunk" /I"thirdparty\Chipmunk2D\include"^ + main.c gamestate.c server.c debugdraw.c^ + thirdparty\enet\callbacks.c thirdparty\enet\compress.c thirdparty\enet\host.c thirdparty\enet\list.c thirdparty\enet\packet.c thirdparty\enet\peer.c thirdparty\enet\protocol.c thirdparty\enet\win32.c Ws2_32.lib winmm.lib^ + %MUNKSRC% \ No newline at end of file diff --git a/flight.exp b/flight.exp new file mode 100644 index 0000000..2d10d36 Binary files /dev/null and b/flight.exp differ diff --git a/flight.lib b/flight.lib new file mode 100644 index 0000000..90c74e5 Binary files /dev/null and b/flight.lib differ diff --git a/gamestate.c b/gamestate.c index 0f2dc6e..5881f86 100644 --- a/gamestate.c +++ b/gamestate.c @@ -1,7 +1,7 @@ +#include #include "types.h" -#include // malloc -#include +#include // assert logging void __assert(bool cond, const char *file, int line, const char *cond_string) { @@ -17,251 +17,257 @@ void __assert(bool cond, const char *file, int line, const char *cond_string) // super try not to depend on external libraries like enet or sokol to keep build process simple, // gamestate its own portable submodule. If need to link to other stuff document here: -// - debug +// - debug.c for debug drawing +// - chipmunk -static void integrate_acceleration(struct Body *body, float dt) +void initialize(struct GameState *gs) { - // position + gs->space = cpSpaceNew(); +} +void destroy(struct GameState *gs) +{ + for (int i = 0; i < MAX_PLAYERS; i++) { - V2 current = body->position; - body->position = V2add(body->position, V2sub(current, body->old_position)); - body->position = V2add(body->position, V2scale(body->acceleration, dt * dt)); - body->old_position = current; + box_destroy(&gs->players[i].box); } - - // rotation + for (int i = 0; i < gs->num_boxes; i++) { - float current = body->rotation; - body->rotation = body->rotation + (current - body->old_rotation); - body->rotation = body->rotation + body->angular_acceleration * dt * dt; - body->old_rotation = current; + box_destroy(&gs->boxes[i]); } + gs->num_boxes = 0; + cpSpaceDestroy(gs->space); + gs->space = NULL; } -struct ProcessBody +struct Box box_new(struct GameState *gs, V2 pos) { - V2 vertices[4]; - struct Body *body; -}; + assert(gs->space != NULL); + float halfbox = BOX_SIZE / 2.0f; + cpBody *body = cpSpaceAddBody(gs->space, cpBodyNew(BOX_MASS, cpMomentForBox(BOX_MASS, BOX_SIZE, BOX_SIZE))); + cpShape *shape = cpBoxShapeNew(body, BOX_SIZE, BOX_SIZE, 0.0f); + cpSpaceAddShape(gs->space, shape); + cpBodySetPosition(body, cpv(pos.x, pos.y)); + + return (struct Box){ + .body = body, + .shape = shape, + }; +} -struct ProcessBody make_process_body(struct Body *from) +void box_destroy(struct Box *box) { - float halfbox = BOX_SIZE / 2.0f; - struct ProcessBody to_return = - { - .vertices = { - // important that the first one is the upper right, used to deduce rotation from vertex position - // @Robust instead of array of vertices have type? like struct with upper_right upper_left etc - V2add(from->position, V2rotate((V2){.x = halfbox, .y = -halfbox}, from->rotation)), // upper right - V2add(from->position, V2rotate((V2){.x = halfbox, .y = halfbox}, from->rotation)), // bottom right - V2add(from->position, V2rotate((V2){.x = -halfbox, .y = halfbox}, from->rotation)), // lower left - V2add(from->position, V2rotate((V2){.x = -halfbox, .y = -halfbox}, from->rotation)), // upper left - }, - .body = from, - }; - return to_return; + cpShapeFree(box->shape); + cpBodyFree(box->body); + box->shape = NULL; + box->body = NULL; } -static void project(struct ProcessBody *from, V2 axis, float *min, float *max) +static V2 cp_to_v2(cpVect v) { - float DotP = V2dot(axis, from->vertices[0]); + return (V2){.x = v.x, .y = v.y}; +} - // Set the minimum and maximum values to the projection of the first vertex - *min = DotP; - *max = DotP; +static cpVect v2_to_cp(V2 v) +{ + return cpv(v.x, v.y); +} - for (int I = 1; I < 4; I++) - { - // Project the rest of the vertices onto the axis and extend - // the interval to the left/right if necessary - DotP = V2dot(axis, from->vertices[I]); +V2 box_pos(struct Box box) +{ + return cp_to_v2(cpBodyGetPosition(box.body)); +} +V2 box_vel(struct Box box) +{ + return cp_to_v2(cpBodyGetVelocity(box.body)); +} +float box_rotation(struct Box box) +{ + return cpBodyGetAngle(box.body); +} +float box_angular_velocity(struct Box box) +{ + return cpBodyGetAngularVelocity(box.body); +} - *min = fmin(DotP, *min); - *max = fmax(DotP, *max); +#define memwrite(out, variable) \ + for (char b = 0; b < sizeof(variable); b++) \ + { \ + **out = ((char *)&variable)[b]; \ + *out += 1; \ } + +#define memread(in, variable_pointer) \ + for (char b = 0; b < sizeof(*variable_pointer); b++) \ + { \ + ((char *)variable_pointer)[b] = **in; \ + *in += 1; \ + } + +void ser_float(char **out, float f) +{ + memwrite(out, f); +} + +void des_float(char **in, float *f) +{ + memread(in, f); +} + +void ser_int(char **out, int i) +{ + memwrite(out, i); } -static float interval_distance(float min_a, float max_a, float min_b, float max_b) +void des_int(char **in, int *i) { - if (min_a < min_b) - return min_b - max_a; - else - return min_a - max_b; + memread(in, i); } -static void move_vertices(V2 *vertices, int num, V2 shift) +void ser_bool(char **out, bool b) { - for (int i = 0; i < num; i++) + **out = (char)b; + *out += 1; +} + +void des_bool(char **in, bool *b) +{ + *b = (bool)**in; + *in += 1; +} + +void ser_V2(char **out, V2 v) +{ + ser_float(out, v.x); + ser_float(out, v.y); +} + +void des_V2(char **in, V2 *v) +{ + des_float(in, &v->x); + des_float(in, &v->y); +} + +void ser_box(char **out, struct Box *b) +{ + // box must not be null, dummy! + assert(b->body != NULL); + ser_V2(out, box_pos(*b)); + ser_V2(out, box_vel(*b)); + ser_float(out, box_rotation(*b)); + ser_float(out, box_angular_velocity(*b)); +} + +// takes gamestate as argument to place box in the gamestates space +void des_box(char **in, struct Box *b, struct GameState *gs) +{ + assert(b->body == NULL); // destroy the box before deserializing into it + V2 pos = {0}; + V2 vel = {0}; + float rot = 0.0f; + float angular_vel = 0.0f; + + des_V2(in, &pos); + des_V2(in, &vel); + des_float(in, &rot); + des_float(in, &angular_vel); + + *b = box_new(gs, pos); + cpBodySetVelocity(b->body, v2_to_cp(vel)); + cpBodySetAngle(b->body, rot); + cpBodySetAngularVelocity(b->body, angular_vel); +} + +void ser_player(char **out, struct Player *p) +{ + ser_bool(out, p->connected); + if (p->connected) { - vertices[i] = V2add(vertices[i], shift); + ser_box(out, &p->box); + ser_V2(out, p->input); } } -void process(struct GameState *gs, float dt) +void des_player(char **in, struct Player *p, struct GameState *gs) { - // process input - int num_bodies = gs->num_boxes; - for (int i = 0; i < MAX_PLAYERS; i++) + des_bool(in, &p->connected); + if (p->connected) { - struct Player *p = &gs->players[i]; - if (!p->connected) - continue; - p->body.acceleration = V2scale(p->input, 5.0f); - p->body.angular_acceleration = p->input.x * 10.0f; - num_bodies += 1; + des_box(in, &p->box, gs); + des_V2(in, &p->input); } +} - // @Robust do this without malloc +// @Robust really think about if <= makes more sense than < here... +#define LEN_CHECK() assert(bytes - original_bytes <= max_len) - struct ProcessBody *bodies = malloc(sizeof *bodies * num_bodies); - int cur_body_index = 0; +void into_bytes(struct ServerToClient *msg, char *bytes, int *out_len, int max_len) +{ + assert(msg->cur_gs != NULL); + assert(msg != NULL); + struct GameState *gs = msg->cur_gs; + char *original_bytes = bytes; + + ser_int(&bytes, msg->your_player); for (int i = 0; i < MAX_PLAYERS; i++) { - struct Player *p = &gs->players[i]; - if (!p->connected) - continue; - integrate_acceleration(&p->body, dt); - bodies[cur_body_index] = make_process_body(&p->body); - cur_body_index++; + ser_player(&bytes, &gs->players[i]); + LEN_CHECK(); } + // @Robust invalid message on num boxes bigger than max boxes + ser_int(&bytes, gs->num_boxes); + LEN_CHECK(); + for (int i = 0; i < gs->num_boxes; i++) { - integrate_acceleration(&gs->boxes[i].body, dt); - bodies[cur_body_index] = make_process_body(&gs->boxes[i].body); - cur_body_index++; + ser_box(&bytes, &gs->boxes[i]); + LEN_CHECK(); } - assert(cur_body_index == num_bodies); + *out_len = bytes - original_bytes; +} - // Collision - // @Robust handle when bodies are overlapping (even perfectly) - for (int i = 0; i < num_bodies; i++) - { - for (int ii = 0; ii < num_bodies; ii++) - { - if (ii == i) - continue; - struct ProcessBody *from = &bodies[i]; - struct ProcessBody *to = &bodies[ii]; - dbg_line(from->body->position, to->body->position); - - float MinDistance = 10000.0f; - - struct Edge - { - struct ProcessBody *parent; - V2 *from; - V2 *to; - }; - - struct ProcessBody *bodies[2] = {from, to}; - bool was_collision = false; - V2 normal = {0}; - struct Edge edge = {0}; - for (int body_i = 0; body_i < 2; body_i++) - { - struct ProcessBody *body = bodies[body_i]; - for (int edge_from_i = 0; edge_from_i < 3; edge_from_i++) - { - int edge_to_i = edge_from_i + 1; - V2 *edge_from = &body->vertices[edge_from_i]; - V2 *edge_to = &body->vertices[edge_to_i]; - - // normal vector of edge - V2 axis = (V2){ - .x = edge_from->y - edge_to->y, - .y = edge_to->x - edge_from->x, - }; - axis = V2normalize(axis); - - float min_from, min_to, max_from, max_to = 0.0f; - project(from, axis, &min_from, &max_from); - project(to, axis, &min_to, &max_to); - - float distance = interval_distance(min_from, min_to, max_from, max_to); - - if (distance > 0.0f) - break; - else if (fabsf(distance) < MinDistance) - { - MinDistance = fabsf(distance); - was_collision = true; - normal = axis; - edge = (struct Edge){ - .parent = &body, - .from = edge_from, - .to = edge_to, - }; - } - } - } - float depth = MinDistance; - if (was_collision) - { - float intersection_depth = from_interval[1] - to_interval[0]; - - move_vertices(from->vertices, 4, V2scale(axis, intersection_depth * -0.5f)); - move_vertices(to->vertices, 4, V2scale(axis, intersection_depth * 0.5f)); - } - } - } +void from_bytes(struct ServerToClient *msg, char *bytes, int max_len) +{ + struct GameState *gs = msg->cur_gs; - // Wall - if (true) + char *original_bytes = bytes; + // destroy and free all chipmunk + destroy(gs); + initialize(gs); + + des_int(&bytes, &msg->your_player); + LEN_CHECK(); + + for (int i = 0; i < MAX_PLAYERS; i++) { - for (int i = 0; i < num_bodies; i++) - { - for (int v_i = 0; v_i < 4; v_i++) - { - V2 *vert = &bodies[i].vertices[v_i]; - if (vert->x > 2.0f) - { - vert->x = 2.0f; - } - } - } + des_player(&bytes, &gs->players[i], gs); + LEN_CHECK(); } - // Correct for differences in vertex position - const int edge_update_iters = 3; - for (int iter = 0; iter < edge_update_iters; iter++) + des_int(&bytes, &gs->num_boxes); + LEN_CHECK(); + + for (int i = 0; i < gs->num_boxes; i++) { - for (int i = 0; i < num_bodies; i++) - { - for (int v_i = 0; v_i < 3; v_i++) - { - int other_v_i = v_i + 1; - V2 *from = &bodies[i].vertices[v_i]; - V2 *to = &bodies[i].vertices[other_v_i]; - - V2 line = V2sub(*to, *from); - float len = V2length(line); - float diff = len - BOX_SIZE; - - line = V2normalize(line); - - *from = V2add(*from, V2scale(line, diff * 0.5f)); - *to = V2sub(*to, V2scale(line, diff * 0.5f)); - } - } + des_box(&bytes, &gs->boxes[i], gs); + LEN_CHECK(); } +} - // Reupdate the positions of the bodies based on how the vertices changed - for (int i = 0; i < num_bodies; i++) +void process(struct GameState *gs, float dt) +{ + assert(gs->space != NULL); + + // process input + for (int i = 0; i < MAX_PLAYERS; i++) { - float upper_right_angle = V2angle(V2sub(bodies[i].vertices[0], bodies[i].body->position)); - bodies[i].body->rotation = upper_right_angle - (PI / 4.0f); - - V2 avg = {0}; - for (int v_i = 0; v_i < 4; v_i++) - { - avg = V2add(avg, bodies[i].vertices[v_i]); - } - avg = V2scale(avg, 1.0f / 4.0f); - bodies[i].body->position = avg; + struct Player *p = &gs->players[i]; + if (!p->connected) + continue; + cpBodyApplyForceAtWorldPoint(p->box.body, v2_to_cp(V2scale(p->input, 5.0f)), v2_to_cp(box_pos(p->box))); } - free(bodies); + cpSpaceStep(gs->space, dt); } \ No newline at end of file diff --git a/main.c b/main.c index a58e1c4..443ab17 100644 --- a/main.c +++ b/main.c @@ -26,6 +26,8 @@ void init(void) { // @BeforeShip make all fprintf into logging to file, warning dialog boxes on failure instead of exit(-1), replace the macros in sokol with this as well, like assert + initialize(&gs); + sg_desc sgdesc = {.context = sapp_sgcontext()}; sg_setup(&sgdesc); if (!sg_isvalid()) @@ -114,17 +116,11 @@ static void frame(void) // and other validation instead of just casting to a struct // "Alignment of structure members can be different even among different compilers on the same platform, let alone different platforms." // ^^ need serialization strategy that accounts for this if multiple platforms is happening https://stackoverflow.com/questions/28455163/how-can-i-portably-send-a-c-struct-through-a-network-socket - struct ServerToClient msg; - if (event.packet->dataLength != sizeof(msg)) - { - Log("Unknown packet size: %zd\n", event.packet->dataLength); - } - else - { - memcpy(&msg, event.packet->data, sizeof(msg)); - myplayer = msg.your_player; - gs = msg.cur_gs; - } + struct ServerToClient msg = { + .cur_gs = &gs, + }; + // @Robust maximum acceptable message size? + from_bytes(&msg, event.packet->data, event.packet->dataLength); enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: @@ -179,7 +175,8 @@ static void frame(void) // camera go to player if (myplayer != -1) { - sgp_translate(-gs.players[myplayer].body.position.x, -gs.players[myplayer].body.position.y); + V2 pos = box_pos(gs.players[myplayer].box); + sgp_translate(-pos.x, -pos.y); } sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); @@ -204,14 +201,14 @@ static void frame(void) continue; sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_push_transform(); - sgp_rotate_at(p->body.rotation, p->body.position.x, p->body.position.y); - sgp_draw_filled_rect(p->body.position.x - halfbox, p->body.position.y - halfbox, BOX_SIZE, BOX_SIZE); + sgp_rotate_at(box_rotation(p->box), box_pos(p->box).x, box_pos(p->box).y); + sgp_draw_filled_rect(box_pos(p->box).x - halfbox, box_pos(p->box).y - halfbox, BOX_SIZE, BOX_SIZE); sgp_pop_transform(); sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); - V2 vel = (V2scale(V2sub(p->body.position, p->body.old_position), 60.0f)); - V2 to = V2add(p->body.position, vel); - sgp_draw_line(p->body.position.x, p->body.position.y, to.x, to.y); + V2 vel = box_vel(p->box); + V2 to = V2add(box_pos(p->box), vel); + sgp_draw_line(box_pos(p->box).x, box_pos(p->box).y, to.x, to.y); } // boxes @@ -219,12 +216,15 @@ static void frame(void) for (int i = 0; i < gs.num_boxes; i++) { sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); - sgp_draw_filled_rect(gs.boxes[i].body.position.x - halfbox, gs.boxes[i].body.position.y - halfbox, BOX_SIZE, BOX_SIZE); + sgp_push_transform(); + sgp_rotate_at(box_rotation(gs.boxes[i]), box_pos(gs.boxes[i]).x, box_pos(gs.boxes[i]).y); + sgp_draw_filled_rect(box_pos(gs.boxes[i]).x - halfbox, box_pos(gs.boxes[i]).y - halfbox, BOX_SIZE, BOX_SIZE); + sgp_pop_transform(); sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); - V2 vel = (V2scale(V2sub(gs.boxes[i].body.position, gs.boxes[i].body.old_position), 60.0f)); - V2 to = V2add(gs.boxes[i].body.position, vel); - sgp_draw_line(gs.boxes[i].body.position.x, gs.boxes[i].body.position.y, to.x, to.y); + V2 vel = box_vel(gs.boxes[i]); + V2 to = V2add(box_pos(gs.boxes[i]), vel); + sgp_draw_line(box_pos(gs.boxes[i]).x, box_pos(gs.boxes[i]).y, to.x, to.y); } } @@ -247,6 +247,7 @@ static void frame(void) void cleanup(void) { + destroy(&gs); sgp_shutdown(); sg_shutdown(); enet_deinitialize(); diff --git a/server.c b/server.c index eca85f0..f29fb3a 100644 --- a/server.c +++ b/server.c @@ -14,31 +14,20 @@ void server(void *data) stm_setup(); struct GameState gs = {0}; + initialize(&gs); // two boxes stacked on top - if (false) + if (true) { - gs.boxes[0] = (struct Box){ - .body = (struct Body){ - .position = (P2){.x = 0.75f, .y = 0.0}}, - }; - gs.boxes[0].body.old_position = gs.boxes[0].body.position; - gs.boxes[1] = (struct Box){ - .body = (struct Body){ - .position = (P2){.x = 0.75f, .y = 0.5f}}, - }; - gs.boxes[1].body.old_position = gs.boxes[1].body.position; + gs.boxes[0] = box_new(&gs, (V2){.x = 0.75f, .y = 0.0}); + gs.boxes[1] = box_new(&gs, (V2){.x = 0.75f, .y = 0.5f}); gs.num_boxes = 2; } // one box - if (true) + if (false) { - gs.boxes[0] = (struct Box){ - .body = (struct Body){ - .position = (P2){.x = 0.75f, .y = 0.0}}, - }; - gs.boxes[0].body.old_position = gs.boxes[0].body.position; + gs.boxes[0] = box_new(&gs, (V2){.x = 0.75f, .y = 0.0}); gs.num_boxes = 1; } @@ -107,11 +96,10 @@ void server(void *data) else { event.peer->data = (void *)player_slot; - gs.players[player_slot] = (struct Player){.body.position = (V2){ - .x = 0.0f, - .y = 1.0f * (float)player_slot, - }}; - gs.players[player_slot].body.old_position = gs.players[player_slot].body.position; + gs.players[player_slot].box = box_new(&gs, (V2){ + .x = 0.0f, + .y = 1.0f * (float)player_slot, + }); gs.players[player_slot].connected = true; } @@ -140,8 +128,10 @@ void server(void *data) break; case ENET_EVENT_TYPE_DISCONNECT: - Log("%" PRId64 " disconnected.\n", (int64_t)event.peer->data); - gs.players[(int64_t)event.peer->data].connected = false; + int player_index = (int64_t)event.peer->data; + Log("%" PRId64 " disconnected player index %d.\n", (int64_t)event.peer->data, player_index); + gs.players[player_index].connected = false; + box_destroy(&gs.players[player_index].box); event.peer->data = NULL; } } @@ -149,13 +139,15 @@ void server(void *data) total_time += (float)stm_sec(stm_diff(stm_now(), last_processed_time)); last_processed_time = stm_now(); - // @Robost if can't process quick enough will be stuck being lagged behind, think of a solution for this... + // @Robost @BeforeShip if can't process quick enough will be stuck being lagged behind, think of a solution for this... while (total_time > TIMESTEP) { process(&gs, TIMESTEP); total_time -= TIMESTEP; } +#define MAX_BYTES_SIZE 2048 * 2 + static char bytes_buffer[MAX_BYTES_SIZE] = {0}; for (int i = 0; i < server->peerCount; i++) { // @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again @@ -164,13 +156,18 @@ void server(void *data) continue; } struct ServerToClient to_send; - to_send.cur_gs = gs; + to_send.cur_gs = &gs; to_send.your_player = (int)(int64_t)server->peers[i].data; - ENetPacket *gamestate_packet = enet_packet_create((void *)&to_send, sizeof(struct ServerToClient), ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT); + + int len = 0; + into_bytes(&to_send, bytes_buffer, &len, MAX_BYTES_SIZE); + + ENetPacket *gamestate_packet = enet_packet_create((void *)bytes_buffer, len, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT); enet_peer_send(&server->peers[i], 0, gamestate_packet); } } + destroy(&gs); enet_host_destroy(server); enet_deinitialize(); } \ No newline at end of file diff --git a/thirdparty/Chipmunk2D b/thirdparty/Chipmunk2D new file mode 160000 index 0000000..352d13c --- /dev/null +++ b/thirdparty/Chipmunk2D @@ -0,0 +1 @@ +Subproject commit 352d13cf6574a63a129ce40e011eec2e248cbe34 diff --git a/tooling.ahk b/tooling.ahk index a4b0255..6a991a1 100644 --- a/tooling.ahk +++ b/tooling.ahk @@ -13,7 +13,7 @@ WinKill, Flight WinActivate, flightbuild If WinActive("flightbuild") { - Send, build_debug.bat && flight.exe --host{Enter} + Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && flight.exe --host{Enter} } return @@ -26,6 +26,6 @@ WinKill, Flight WinActivate, flightbuild If WinActive("flightbuild") { - Send, build_debug.bat && START /B flight.exe && flight.exe --host{Enter} + Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && START /B flight.exe && flight.exe --host{Enter} } return \ No newline at end of file diff --git a/types.h b/types.h index c349095..85b630b 100644 --- a/types.h +++ b/types.h @@ -1,5 +1,10 @@ #pragma once +#define MAX_PLAYERS 4 +#define BOX_SIZE 0.5f +#define MAX_BOXES 128 +#define BOX_MASS 1.0f + // @Robust remove this include somehow, needed for sqrt and cos #include @@ -15,6 +20,16 @@ typedef sgp_vec2 sgp_point; #endif +#ifndef CHIPMUNK_H +typedef void cpSpace; +typedef void cpBody; +typedef void cpShape; + +extern void cpShapeFree(cpShape *); +extern void cpBodyFree(cpBody *); +extern void cpSpaceFree(cpSpace *); +#endif + #include #ifndef _STDBOOL @@ -31,43 +46,30 @@ typedef sgp_point P2; #define Log(...) \ fprintf(stdout, "%s:%d | ", __FILE__, __LINE__); \ fprintf(stdout, __VA_ARGS__) -#define MAX_BOXES 32 -#define MAX_PLAYERS 4 -#define BOX_SIZE 0.5f -struct Body +struct Box { - P2 position; - P2 old_position; - - float rotation; - float old_rotation; - - V2 acceleration; - float angular_acceleration; -}; - -struct Player -{ - struct Body body; - bool connected; - V2 input; + cpBody *body; + cpShape *shape; }; +// gotta update the serialization functions when this changes struct GameState { - struct Player players[MAX_PLAYERS]; - - int num_boxes; - struct Box + cpSpace *space; + struct Player { - struct Body body; - } boxes[MAX_BOXES]; + struct Box box; + bool connected; + V2 input; + } players[MAX_PLAYERS]; + int num_boxes; + struct Box boxes[MAX_BOXES]; }; struct ServerToClient { - struct GameState cur_gs; + struct GameState *cur_gs; int your_player; }; @@ -80,7 +82,19 @@ struct ClientToServer void server(void *data); // gamestate +void initialize(struct GameState *gs); // must do this to place boxes into it and process +void destroy(struct GameState *gs); void process(struct GameState *gs, float dt); // does in place +void into_bytes(struct ServerToClient *gs, char *out_bytes, int *out_len, int max_len); +void from_bytes(struct ServerToClient *gs, char *bytes, int max_len); + +// box +struct Box box_new(struct GameState *gs, V2 pos); +void box_destroy(struct Box * box); +V2 box_pos(struct Box box); +V2 box_vel(struct Box box); +float box_rotation(struct Box box); +float box_angular_velocity(struct Box box); // debug draw void dbg_drawall();