Slight reconstruction/abstraction. Getting close to connecting to other sessions etc.
This commit is contained in:
87
src/instance/game_instance.c
Normal file
87
src/instance/game_instance.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "game_instance.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define INPUT_QUEUE_CAPACITY 8
|
||||
|
||||
void game_instance_init(Game_Instance *instance) {
|
||||
instance->local_player_index = 0xFFFF;
|
||||
// TODO: SS - Init input-queue.
|
||||
instance->simulation_accumulator = 0.0f; // TODO: SS - Should probably be moved to the Ingame context.
|
||||
instance->game_session = NULL;
|
||||
memset(&instance->game_networking, 0, sizeof(Game_Networking));
|
||||
|
||||
squeue_init(&instance->local_input_queue, 4, sizeof(Simulation_Game_Input));
|
||||
}
|
||||
|
||||
void game_instance_dispose(Game_Instance *instance) {
|
||||
squeue_free(&instance->local_input_queue);
|
||||
}
|
||||
|
||||
bool game_instance_host_session(Game_Instance *instance, const Game_Session_Settings settings) {
|
||||
assert(instance != NULL);
|
||||
|
||||
printf("Trying to host an %s session ...\n", settings.online ? "online" : "offline");
|
||||
|
||||
if(instance->game_session != NULL) {
|
||||
printf("Failed. A session is already active.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
instance->game_session = (Game_Session *)calloc(1, sizeof(Game_Session));
|
||||
|
||||
if(settings.online) {
|
||||
if(instance->game_networking.api != NULL) {
|
||||
printf("Failed. Network is already active.\n");
|
||||
free(instance->game_session);
|
||||
instance->game_session = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!networking_try_host(&instance->game_networking, instance->game_session, settings)) {
|
||||
printf("Failed to host session.\n");
|
||||
free(instance->game_session);
|
||||
instance->game_session = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
game_session_init(instance->game_session, settings);
|
||||
}
|
||||
|
||||
assert(game_session_create_player(instance->game_session, &instance->local_player_index)); // Create the host (you!).
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool game_instance_join_session(Game_Instance *instance, const char *session_id) {
|
||||
assert(instance != NULL);
|
||||
|
||||
printf("Trying to join a session ...\n");
|
||||
|
||||
if(instance->game_session != NULL) {
|
||||
printf("Failed. A session is already active.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(instance->game_networking.api != NULL) {
|
||||
printf("Failed. Network is already active.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool game_instance_push_local_input(Game_Instance *instance, Simulation_Game_Input input) {
|
||||
return squeue_push(&instance->local_input_queue, (void *)&input);
|
||||
}
|
||||
|
||||
bool game_instance_pop_local_input(Game_Instance *instance, Simulation_Game_Input *out_input) {
|
||||
Simulation_Game_Input input = {0};
|
||||
if(!squeue_pop(&instance->local_input_queue, (void *)&input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_input = input;
|
||||
return true;
|
||||
}
|
||||
32
src/instance/game_instance.h
Normal file
32
src/instance/game_instance.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef GAME_INSTANCE_H
|
||||
#define GAME_INSTANCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "session/networking.h"
|
||||
#include "session/game_session.h"
|
||||
|
||||
#include "shared/squeue.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t local_player_index;
|
||||
SQueue local_input_queue;
|
||||
|
||||
double simulation_accumulator;
|
||||
|
||||
Game_Networking game_networking;
|
||||
Game_Session *game_session;
|
||||
} Game_Instance;
|
||||
|
||||
void game_instance_init(Game_Instance *instance);
|
||||
void game_instance_dispose(Game_Instance *instance);
|
||||
|
||||
bool game_instance_host_session(Game_Instance *instance, const Game_Session_Settings settings);
|
||||
bool game_instance_join_session(Game_Instance *instance, const char *session_id);
|
||||
|
||||
// TODO: SS - stop_session()
|
||||
|
||||
bool game_instance_push_local_input(Game_Instance *instance, Simulation_Game_Input input);
|
||||
bool game_instance_pop_local_input(Game_Instance *instance, Simulation_Game_Input *out_input);
|
||||
|
||||
#endif
|
||||
@@ -205,7 +205,7 @@ static int compare_keys(const void *key1, const void *key2)
|
||||
|
||||
static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size)
|
||||
{
|
||||
snprintf(key, key_size, "%p", json);
|
||||
snprintf(key, key_size, "%p", (void *)json);
|
||||
if (hashtable_get(parents, key))
|
||||
return -1;
|
||||
|
||||
|
||||
21
src/main.c
21
src/main.c
@@ -6,6 +6,9 @@
|
||||
#include "presentation/states/state_main_menu.h"
|
||||
|
||||
#include "raylib.h"
|
||||
#include "session/networking.h"
|
||||
|
||||
#include "instance/game_instance.h"
|
||||
|
||||
int main() {
|
||||
InitWindow(1280, 720, "snejk");
|
||||
@@ -14,10 +17,18 @@ int main() {
|
||||
|
||||
bool should_quit_game = false;
|
||||
|
||||
Presentation_State_Ingame_Context presentation_state_ingame_ctx = (Presentation_State_Ingame_Context) {
|
||||
};
|
||||
Game_Instance local_game_instance;
|
||||
memset(&local_game_instance, 0, sizeof(Game_Instance));
|
||||
|
||||
game_instance_init(&local_game_instance);
|
||||
|
||||
Presentation_State_Ingame_Context presentation_state_ingame_ctx;
|
||||
memset(&presentation_state_ingame_ctx, 0, sizeof(Presentation_State_Ingame_Context));
|
||||
|
||||
Presentation_State_Main_Menu_Context presentation_state_main_menu_ctx = {
|
||||
.should_quit_game = &should_quit_game,
|
||||
.game_instance = &local_game_instance,
|
||||
.ingame_ctx = &presentation_state_ingame_ctx
|
||||
};
|
||||
|
||||
presentation_state_ingame_init(&presentation_state_ingame_ctx);
|
||||
@@ -34,6 +45,10 @@ int main() {
|
||||
if(presentation_state_machine.current != NULL && presentation_state_machine.current->tick != NULL) {
|
||||
presentation_state_machine.current->tick(presentation_state_machine.current);
|
||||
}
|
||||
|
||||
if(IsKeyPressed(KEY_F)) {
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
// Render.
|
||||
BeginDrawing();
|
||||
@@ -47,6 +62,8 @@ int main() {
|
||||
|
||||
assert(presentation_state_machine_go_to(NULL));
|
||||
CloseWindow();
|
||||
|
||||
game_instance_dispose(&local_game_instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -20,24 +20,6 @@ static void state_enter(Presentation_State *state) {
|
||||
(void)ctx;
|
||||
|
||||
printf("Entered ingame.\n");
|
||||
|
||||
printf("Setting up session ...\n");
|
||||
|
||||
assert(g_current_session != NULL);
|
||||
Game_Session_Settings *settings = &g_current_session->settings;
|
||||
printf(
|
||||
"Singleplayer? %i.\n"
|
||||
"Settings:\n"
|
||||
"- Seed: %u\n"
|
||||
"- Level width: %u, height: %u\n"
|
||||
"- Max players: %u\n"
|
||||
,
|
||||
g_current_session->is_singleplayer,
|
||||
settings->seed,
|
||||
settings->level_width, settings->level_height,
|
||||
settings->max_players
|
||||
);
|
||||
|
||||
|
||||
printf("Setting up context ...\n");
|
||||
ctx->main_camera = (Camera2D) {
|
||||
@@ -65,23 +47,46 @@ static void state_tick(Presentation_State *state) {
|
||||
Presentation_State_Ingame_Context *ctx = (Presentation_State_Ingame_Context *)state->context;
|
||||
(void)ctx;
|
||||
|
||||
Game_Session *session = g_current_session;
|
||||
Game_Instance *instance = ctx->game_instance;
|
||||
assert(instance != NULL);
|
||||
Game_Session *session = instance->game_session;
|
||||
assert(session != NULL);
|
||||
|
||||
{ // Push local input to queue.
|
||||
game_session_enqueue_player_input(session, session->local_player_index, (Simulation_Game_Input) {
|
||||
Simulation_Game_Input input = (Simulation_Game_Input) { // NOTE: SS - This needs to be slightly modified to support N local players.
|
||||
.up = IsKeyDown(KEY_UP) || IsKeyDown(KEY_W),
|
||||
.down = IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S),
|
||||
.right = IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D),
|
||||
.left = IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)
|
||||
});
|
||||
};
|
||||
|
||||
if(!simulation_input_equal(input, ctx->prev_local_input)) {
|
||||
game_instance_push_local_input(instance, input);
|
||||
ctx->prev_local_input = input;
|
||||
}
|
||||
}
|
||||
|
||||
const double delta_time = GetFrameTime();
|
||||
ctx->simulation_accumulator += delta_time;
|
||||
|
||||
const double sim_dt = 1.0f / session->settings.tickrate;
|
||||
|
||||
while (ctx->simulation_accumulator >= sim_dt) {
|
||||
// Pop input from instance's local_input_queue and set the local player's input to it, if we have one.
|
||||
Simulation_Game_Input input = {0};
|
||||
if(game_instance_pop_local_input(instance, &input)) {
|
||||
// TODO: SS - We should probably check if this input is invalid for the snake. (pressing "go right" when going left, for example.)
|
||||
// If it is invalid, the next input in the queue should be tried.
|
||||
game_session_set_player_input(session, instance->local_player_index, input);
|
||||
}
|
||||
|
||||
game_session_tick(session);
|
||||
ctx->simulation_accumulator -= sim_dt;
|
||||
}
|
||||
|
||||
double delta_time = GetFrameTime();
|
||||
game_session_update(session, delta_time);
|
||||
|
||||
{ // TEMP: SS
|
||||
if(IsKeyPressed(KEY_TAB)) {
|
||||
ctx->debug_render_match_state = !ctx->debug_render_match_state;
|
||||
ctx->debug_draw_session_details = !ctx->debug_draw_session_details;
|
||||
}
|
||||
|
||||
if(IsKeyPressed(KEY_ESCAPE)) {
|
||||
@@ -102,7 +107,9 @@ static void state_render(Presentation_State *state) {
|
||||
|
||||
ClearBackground((Color) { 240, 236, 226, 255 });
|
||||
|
||||
Simulation_World *sim_world = &g_current_session->simulation_world;
|
||||
Game_Instance *instance = ctx->game_instance;
|
||||
Game_Session *session = instance->game_session;
|
||||
Simulation_World *sim_world = &session->simulation_world;
|
||||
assert(sim_world != NULL);
|
||||
|
||||
Game_World *world = sim_world->game_world;
|
||||
@@ -222,7 +229,7 @@ static void state_render(Presentation_State *state) {
|
||||
// TODO: SS - Don't draw player-name if playing by yourself.
|
||||
// TODO: SS - Don't draw your own player-name, only others.
|
||||
{ // Draw player-name.
|
||||
const char *player_name = "mirakel"; // NOTE: SS - Hardcoded.
|
||||
const char *player_name = "player"; // NOTE: SS - Hardcoded.
|
||||
const uint32_t font_size = 8;
|
||||
int text_width = MeasureText(player_name, font_size);
|
||||
DrawText(player_name, pres_x - (float)text_width/2.0f + 4, pres_y - 16, font_size, (Color) { 255, 255, 255, 128 });
|
||||
@@ -255,7 +262,7 @@ static void state_render(Presentation_State *state) {
|
||||
},
|
||||
(Rectangle) { // Destination.
|
||||
pres_x + origin.x,
|
||||
pres_y + origin.y + ENTITY_PRESENTATION_Y_OFFSET - ((sin(GetTime() * 12) + 1)/2) * 1,
|
||||
pres_y + origin.y + ENTITY_PRESENTATION_Y_OFFSET - ((sin((GetTime() + (x + y)) * 12) + 1)/2) * 1,
|
||||
GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE
|
||||
},
|
||||
@@ -271,11 +278,33 @@ static void state_render(Presentation_State *state) {
|
||||
|
||||
// TODO: SS - Switch on 'sim_world->match_state'.
|
||||
|
||||
if(ctx->debug_render_match_state) {
|
||||
char buf[512];
|
||||
snprintf(&buf[0], sizeof(buf), "Match-state: %i. Tick: %lu.", sim_world->match_state, sim_world->tick);
|
||||
if(ctx->debug_draw_session_details) {
|
||||
char buf[1024];
|
||||
snprintf(&buf[0], sizeof(buf),
|
||||
"Match-state: %i\n"
|
||||
"Tick: %lu\n"
|
||||
"\n"
|
||||
"Seed: %u\n"
|
||||
"Level: %ux%u\n"
|
||||
"Tickrate: %.2f\n"
|
||||
"\n"
|
||||
|
||||
DrawText(buf, 16, 16, 8, RED);
|
||||
// TODO: SS - This should only be shown when playing online. Other things should be shown in the cases below;
|
||||
// When playing offline/singleplayer you can only be one player.
|
||||
// When playing local-multiplayer, you control multiple players from the same computer/client/instance.
|
||||
"Local player: %u (host? %s)\n"
|
||||
"Player count: %u / %u\n"
|
||||
,
|
||||
sim_world->match_state, sim_world->tick,
|
||||
sim_world->game_world->seed,
|
||||
sim_world->game_world->grid.width, sim_world->game_world->grid.height,
|
||||
session->settings.tickrate,
|
||||
instance->local_player_index, instance->local_player_index == 0 ? "true" : "false", // NOTE: SS - You're the host if you're player 0.
|
||||
game_session_get_amount_of_active_players(session), sim_world->max_players
|
||||
);
|
||||
|
||||
DrawText(buf, 17, 17, 8, BLACK);
|
||||
DrawText(buf, 16, 16, 8, WHITE);
|
||||
}
|
||||
}
|
||||
EndMode2D();
|
||||
@@ -292,7 +321,7 @@ static void state_exit(Presentation_State *state) {
|
||||
UnloadTexture(ctx->texture_snake_head);
|
||||
UnloadTexture(ctx->texture_snake_body);
|
||||
|
||||
game_session_destroy();
|
||||
ctx->game_instance = NULL;
|
||||
}
|
||||
|
||||
Presentation_State presentation_state_ingame;
|
||||
|
||||
@@ -5,8 +5,13 @@
|
||||
#include "simulation/simulation_world.h"
|
||||
|
||||
#include "raylib.h"
|
||||
#include "instance/game_instance.h"
|
||||
|
||||
typedef struct {
|
||||
Game_Instance *game_instance;
|
||||
double simulation_accumulator;
|
||||
Simulation_Game_Input prev_local_input;
|
||||
|
||||
Camera2D main_camera;
|
||||
|
||||
// Textures.
|
||||
@@ -17,8 +22,8 @@ typedef struct {
|
||||
Texture2D texture_snake_body;
|
||||
|
||||
// Debug.
|
||||
bool debug_render_match_state;
|
||||
|
||||
bool debug_draw_session_details;
|
||||
|
||||
} Presentation_State_Ingame_Context;
|
||||
|
||||
void presentation_state_ingame_init(Presentation_State_Ingame_Context *ctx);
|
||||
|
||||
@@ -2,39 +2,58 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raygui.h"
|
||||
|
||||
#include "session/networking.h"
|
||||
|
||||
static void state_enter(Presentation_State *state) {
|
||||
Presentation_State_Main_Menu_Context *ctx = (Presentation_State_Main_Menu_Context *)state->context;
|
||||
(void)ctx;
|
||||
|
||||
ctx->mode = Main_Menu_Mode_Home;
|
||||
|
||||
// if(ctx->game_session != NULL) {
|
||||
// if(ctx->game_session->is_singleplayer) {
|
||||
|
||||
// }
|
||||
// else {
|
||||
// if(ctx->game_session->is_host) {
|
||||
// networking_stop_hosting(ctx->game_networking);
|
||||
// }
|
||||
// else {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// game_session_dispose(ctx->game_session);
|
||||
// ctx->game_session = NULL;
|
||||
// }
|
||||
}
|
||||
|
||||
static void state_tick(Presentation_State *state) {
|
||||
Presentation_State_Main_Menu_Context *ctx = (Presentation_State_Main_Menu_Context *)state->context;
|
||||
|
||||
{ // DEBUG
|
||||
if(IsKeyPressed(KEY_P)) {
|
||||
ctx->is_singleplayer = true;
|
||||
ctx->mode = Main_Menu_Mode_Game_Setup;
|
||||
game_session_init_default_settings(ctx->is_singleplayer, &ctx->session_settings);
|
||||
// { // DEBUG
|
||||
// if(IsKeyPressed(KEY_P)) {
|
||||
// game_session_init_default_settings(true, &ctx->session_settings);
|
||||
|
||||
game_session_create(
|
||||
ctx->is_singleplayer,
|
||||
!ctx->is_singleplayer,
|
||||
ctx->session_settings
|
||||
);
|
||||
// assert(ctx->game_session == NULL);
|
||||
// ctx->game_session = (Game_Session *)calloc(1, sizeof(Game_Session));
|
||||
|
||||
presentation_state_machine_go_to(&presentation_state_ingame);
|
||||
}
|
||||
}
|
||||
// game_session_init(
|
||||
// ctx->game_session,
|
||||
// ctx->session_settings
|
||||
// );
|
||||
|
||||
// ctx->ingame_ctx->game_instance = ctx->game_instance;
|
||||
// presentation_state_machine_go_to(&presentation_state_ingame);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
bool editing_width = false;
|
||||
|
||||
static void state_render(Presentation_State *state) {
|
||||
Presentation_State_Main_Menu_Context *ctx = (Presentation_State_Main_Menu_Context *)state->context;
|
||||
|
||||
@@ -59,17 +78,15 @@ static void state_render(Presentation_State *state) {
|
||||
break;
|
||||
}
|
||||
case Main_Menu_Mode_Singleplayer: {
|
||||
ctx->is_singleplayer = true;
|
||||
ctx->mode = Main_Menu_Mode_Game_Setup;
|
||||
game_session_init_default_settings(ctx->is_singleplayer, &ctx->session_settings);
|
||||
game_session_init_default_settings(false, &ctx->session_settings);
|
||||
|
||||
break;
|
||||
}
|
||||
case Main_Menu_Mode_Multiplayer: {
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 0), 128, BUTTON_HEIGHT }, "Host")) {
|
||||
ctx->is_singleplayer = false;
|
||||
ctx->mode = Main_Menu_Mode_Game_Setup;
|
||||
game_session_init_default_settings(ctx->is_singleplayer, &ctx->session_settings);
|
||||
game_session_init_default_settings(true, &ctx->session_settings);
|
||||
}
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 1), 128, BUTTON_HEIGHT }, "Join")) {
|
||||
ctx->mode = Main_Menu_Mode_Multiplayer_Join;
|
||||
@@ -94,18 +111,16 @@ static void state_render(Presentation_State *state) {
|
||||
// Modify 'ctx->session_settings'.
|
||||
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 0), 128, BUTTON_HEIGHT }, "Play")) {
|
||||
// Set up the ingame-context and transition to the ingame-state.
|
||||
// NOTE: SS - We might need to wait before transitioning when playing multiplayer.
|
||||
game_session_create(
|
||||
ctx->is_singleplayer,
|
||||
!ctx->is_singleplayer,
|
||||
ctx->session_settings
|
||||
);
|
||||
|
||||
presentation_state_machine_go_to(&presentation_state_ingame);
|
||||
if(game_instance_host_session(ctx->game_instance, ctx->session_settings)) { // Settings indicate whether or not this is an online or offline game.
|
||||
ctx->ingame_ctx->game_instance = ctx->game_instance;
|
||||
presentation_state_machine_go_to(&presentation_state_ingame);
|
||||
}
|
||||
else {
|
||||
printf("Failed to play.\n");
|
||||
}
|
||||
}
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 1), 128, BUTTON_HEIGHT }, "Cancel")) {
|
||||
ctx->mode = ctx->is_singleplayer ? Main_Menu_Mode_Home : Main_Menu_Mode_Multiplayer;
|
||||
ctx->mode = ctx->session_settings.max_players == 1 ? Main_Menu_Mode_Home : Main_Menu_Mode_Multiplayer;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -115,6 +130,8 @@ static void state_render(Presentation_State *state) {
|
||||
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 1), 128, BUTTON_HEIGHT }, "Connect")) {
|
||||
printf("TODO: SS - Connect to session id.\n");
|
||||
const char *session_id = "TEMP00"; // TEMP
|
||||
game_instance_join_session(ctx->game_instance, session_id);
|
||||
}
|
||||
|
||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 2), 128, BUTTON_HEIGHT }, "Cancel")) {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#define PRES_STATE_MAIN_MENU_H
|
||||
|
||||
#include "states.h"
|
||||
#include "session/game_session.h"
|
||||
#include "state_ingame.h"
|
||||
#include "instance/game_instance.h"
|
||||
|
||||
typedef enum {
|
||||
Main_Menu_Mode_Home,
|
||||
@@ -16,10 +17,13 @@ typedef enum {
|
||||
typedef struct {
|
||||
Main_Menu_Mode mode;
|
||||
|
||||
bool is_singleplayer;
|
||||
Game_Session_Settings session_settings;
|
||||
|
||||
|
||||
Game_Instance *game_instance;
|
||||
|
||||
bool *should_quit_game;
|
||||
|
||||
Presentation_State_Ingame_Context *ingame_ctx;
|
||||
} Presentation_State_Main_Menu_Context;
|
||||
|
||||
void presentation_state_main_menu_init(Presentation_State_Main_Menu_Context *ctx);
|
||||
|
||||
@@ -6,22 +6,14 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "shared/squeue.h"
|
||||
void game_session_init(Game_Session *session, Game_Session_Settings settings) {
|
||||
assert(session != NULL);
|
||||
|
||||
#define INPUT_QUEUE_CAPACITY 8
|
||||
|
||||
Game_Session *g_current_session = NULL;
|
||||
|
||||
void game_session_create(bool is_singleplayer, bool is_host, Game_Session_Settings settings) {
|
||||
assert(g_current_session == NULL);
|
||||
|
||||
Game_Session *session = (Game_Session *)calloc(1, sizeof(Game_Session));
|
||||
session->is_singleplayer = is_singleplayer;
|
||||
session->is_host = is_host;
|
||||
session->settings = settings;
|
||||
|
||||
session->simulation_world = simulation_create_world(
|
||||
session->settings.seed,
|
||||
session->settings.online,
|
||||
session->settings.max_players,
|
||||
session->settings.level_width,
|
||||
session->settings.level_height
|
||||
@@ -29,66 +21,36 @@ void game_session_create(bool is_singleplayer, bool is_host, Game_Session_Settin
|
||||
|
||||
session->players = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
||||
session->players_prev = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
||||
|
||||
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||
assert(squeue_init(
|
||||
&session->players[i].input_queue,
|
||||
INPUT_QUEUE_CAPACITY,
|
||||
sizeof(Simulation_Game_Input)
|
||||
));
|
||||
|
||||
// Intentionally not initializing players_prev's input_queue.
|
||||
}
|
||||
|
||||
{ // TEMP
|
||||
session->local_player_index = 0;
|
||||
assert(game_session_create_player(session, &session->local_player_index));
|
||||
}
|
||||
|
||||
session->simulation_accumulator = 0.0f;
|
||||
|
||||
g_current_session = session;
|
||||
|
||||
printf("New Game_Session created.\n");
|
||||
}
|
||||
|
||||
void game_session_destroy() {
|
||||
Game_Session *session = g_current_session;
|
||||
|
||||
void game_session_dispose(Game_Session *session) {
|
||||
if(session == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
simulation_destroy_world(&session->simulation_world);
|
||||
|
||||
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||
squeue_free(&session->players[i].input_queue);
|
||||
|
||||
// Intentionally not freeing players_prev's input_queue.
|
||||
}
|
||||
|
||||
free(session->players);
|
||||
session->players = NULL;
|
||||
free(session->players_prev);
|
||||
session->players_prev = NULL;
|
||||
|
||||
free(session);
|
||||
g_current_session = NULL;
|
||||
memset(session, 0, sizeof(Game_Session));
|
||||
}
|
||||
|
||||
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings) {
|
||||
void game_session_init_default_settings(bool online, Game_Session_Settings *out_settings) {
|
||||
out_settings->seed = 1337; // TODO: SS - Randomize.
|
||||
out_settings->online = online;
|
||||
out_settings->tickrate = 10.0;
|
||||
out_settings->level_width = 64;
|
||||
out_settings->level_height = 32;
|
||||
out_settings->max_players = is_singleplayer ? 1 : 8;
|
||||
out_settings->max_players = online ? 8 : 2;
|
||||
}
|
||||
|
||||
static void game_session_tick(Game_Session *session) {
|
||||
// Update input.
|
||||
void game_session_tick(Game_Session *session) {
|
||||
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||
Game_Session_Player *session_player = &session->players[i];
|
||||
|
||||
|
||||
{ // Check if any players have joined/disconnected by comparing against the previous session_player.
|
||||
Game_Session_Player *session_player_prev = &session->players_prev[i];
|
||||
|
||||
@@ -107,21 +69,17 @@ static void game_session_tick(Game_Session *session) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!session_player->active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Simulation_Game_Input input = {0};
|
||||
if(squeue_pop(&session_player->input_queue, &input)) {
|
||||
// We got an input.
|
||||
|
||||
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
||||
.type = Simulation_Command_Type_Set_Player_Input,
|
||||
.player_id = i,
|
||||
.player_input = input,
|
||||
});
|
||||
}
|
||||
|
||||
// Update input.
|
||||
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
||||
.type = Simulation_Command_Type_Set_Player_Input,
|
||||
.player_id = i,
|
||||
.player_input = session_player->input,
|
||||
});
|
||||
}
|
||||
|
||||
// Tick.
|
||||
@@ -131,17 +89,6 @@ static void game_session_tick(Game_Session *session) {
|
||||
memcpy(session->players_prev, session->players, sizeof(Game_Session_Player) * session->settings.max_players);
|
||||
}
|
||||
|
||||
void game_session_update(Game_Session *session, const double delta_time) {
|
||||
session->simulation_accumulator += delta_time;
|
||||
|
||||
const double sim_dt = 1.0 / session->settings.tickrate;
|
||||
|
||||
while (session->simulation_accumulator >= sim_dt) {
|
||||
game_session_tick(session);
|
||||
session->simulation_accumulator -= sim_dt;
|
||||
}
|
||||
}
|
||||
|
||||
static Game_Session_Player *game_session_get_player_from_id(Game_Session *session, uint16_t player_index) {
|
||||
assert(session != NULL);
|
||||
if(player_index >= session->settings.max_players) {
|
||||
@@ -151,11 +98,19 @@ static Game_Session_Player *game_session_get_player_from_id(Game_Session *sessio
|
||||
return &session->players[player_index];
|
||||
}
|
||||
|
||||
Game_Session_Player *game_session_get_local_player(Game_Session *session) {
|
||||
uint16_t game_session_get_amount_of_active_players(Game_Session *session) {
|
||||
assert(session != NULL);
|
||||
return game_session_get_player_from_id(session, session->local_player_index);
|
||||
}
|
||||
uint16_t amount = 0;
|
||||
|
||||
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||
Game_Session_Player *player = &session->players[i];
|
||||
if(player->active) {
|
||||
amount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index) {
|
||||
assert(session != NULL);
|
||||
@@ -191,23 +146,10 @@ void game_session_destroy_player(Game_Session *session, uint16_t player_index) {
|
||||
memset(player, 0, sizeof(Game_Session_Player));
|
||||
}
|
||||
|
||||
bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input) {
|
||||
bool game_session_set_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input) {
|
||||
Game_Session_Player *player = game_session_get_player_from_id(session, player_index);
|
||||
assert(player != NULL);
|
||||
|
||||
if(simulation_input_equal(player->most_recent_input, input)) {
|
||||
// Ignore 'input' if it's equal to the most recent input. This way we avoid duplicates.
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: SS - Check if 'input' is a valid "snake-move".
|
||||
// Inputting right when going left will sadly be "okay" here which will make the game
|
||||
// feel less responsive.
|
||||
|
||||
if(!squeue_push(&player->input_queue, (void *)&input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
player->most_recent_input = input;
|
||||
player->input = input;
|
||||
return true;
|
||||
}
|
||||
@@ -13,54 +13,46 @@
|
||||
typedef struct {
|
||||
bool active;
|
||||
|
||||
SQueue input_queue;
|
||||
Simulation_Game_Input most_recent_input; // Exclusively used to make sure that the input-queue doesn't get filled with duplicated inputs.
|
||||
Simulation_Game_Input input;
|
||||
} Game_Session_Player;
|
||||
|
||||
typedef struct {
|
||||
uint32_t seed;
|
||||
|
||||
double tickrate;
|
||||
|
||||
bool online;
|
||||
|
||||
uint16_t level_width;
|
||||
uint16_t level_height;
|
||||
|
||||
double tickrate;
|
||||
|
||||
uint8_t max_players;
|
||||
|
||||
|
||||
// ..
|
||||
} Game_Session_Settings;
|
||||
|
||||
typedef struct {
|
||||
bool is_singleplayer;
|
||||
bool is_host;
|
||||
|
||||
Game_Session_Settings settings;
|
||||
|
||||
Simulation_World simulation_world;
|
||||
double simulation_accumulator;
|
||||
|
||||
|
||||
Game_Session_Player *players;
|
||||
Game_Session_Player *players_prev;
|
||||
uint16_t local_player_index;
|
||||
|
||||
// TODO: SS - Local + remote input-queue.
|
||||
Simulation_World simulation_world;
|
||||
} Game_Session;
|
||||
|
||||
extern Game_Session *g_current_session;
|
||||
void game_session_init(Game_Session *session, Game_Session_Settings settings);
|
||||
void game_session_dispose(Game_Session *session);
|
||||
|
||||
void game_session_create(bool is_singleplayer, bool is_host, Game_Session_Settings settings);
|
||||
void game_session_destroy();
|
||||
void game_session_init_default_settings(bool online, Game_Session_Settings *out_settings);
|
||||
|
||||
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings);
|
||||
void game_session_tick(Game_Session *session);
|
||||
|
||||
void game_session_update(Game_Session *session, const double delta_time);
|
||||
|
||||
Game_Session_Player *game_session_get_local_player(Game_Session *session);
|
||||
uint16_t game_session_get_amount_of_active_players(Game_Session *session);
|
||||
|
||||
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index);
|
||||
void game_session_destroy_player(Game_Session *session, uint16_t player_index);
|
||||
|
||||
bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input);
|
||||
bool game_session_set_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "MultiplayerApi.h"
|
||||
#include "multiplayer_api.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -15,18 +15,19 @@
|
||||
typedef struct ListenerNode {
|
||||
int id;
|
||||
MultiplayerListener cb;
|
||||
void *user_data;
|
||||
void *context;
|
||||
struct ListenerNode *next;
|
||||
} ListenerNode;
|
||||
|
||||
typedef struct ListenerSnapshot {
|
||||
MultiplayerListener cb;
|
||||
void *user_data;
|
||||
void *context;
|
||||
} ListenerSnapshot;
|
||||
|
||||
struct MultiplayerApi {
|
||||
char *server_host;
|
||||
uint16_t server_port;
|
||||
char identifier[37];
|
||||
int sockfd;
|
||||
char *session_id;
|
||||
|
||||
@@ -48,12 +49,19 @@ static void *recv_thread_main(void *arg);
|
||||
static void process_line(MultiplayerApi *api, const char *line);
|
||||
static int start_recv_thread(MultiplayerApi *api);
|
||||
|
||||
MultiplayerApi *mp_api_create(const char *server_host, uint16_t server_port) {
|
||||
MultiplayerApi *api = (MultiplayerApi *)calloc(1, sizeof(MultiplayerApi));
|
||||
MultiplayerApi *mp_api_create(const char *server_host, uint16_t server_port, const char *identifier)
|
||||
{
|
||||
int len = strlen(identifier);
|
||||
if (len != 36) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MultiplayerApi *api = (MultiplayerApi *)calloc(1, sizeof(MultiplayerApi));
|
||||
if (!api) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (server_host) {
|
||||
api->server_host = strdup(server_host);
|
||||
} else {
|
||||
@@ -66,6 +74,9 @@ MultiplayerApi *mp_api_create(const char *server_host, uint16_t server_port) {
|
||||
}
|
||||
|
||||
api->server_port = server_port;
|
||||
|
||||
strncpy(api->identifier, identifier, 37);
|
||||
|
||||
api->sockfd = -1;
|
||||
api->session_id = NULL;
|
||||
api->recv_thread_started = 0;
|
||||
@@ -117,6 +128,7 @@ void mp_api_destroy(MultiplayerApi *api) {
|
||||
}
|
||||
|
||||
int mp_api_host(MultiplayerApi *api,
|
||||
json_t *data,
|
||||
char **out_session,
|
||||
char **out_clientId,
|
||||
json_t **out_data) {
|
||||
@@ -129,9 +141,16 @@ int mp_api_host(MultiplayerApi *api,
|
||||
json_t *root = json_object();
|
||||
if (!root) return MP_API_ERR_IO;
|
||||
|
||||
json_object_set_new(root, "session", json_null());
|
||||
json_object_set_new(root, "identifier", json_string(api->identifier));
|
||||
json_object_set_new(root, "cmd", json_string("host"));
|
||||
json_object_set_new(root, "data", json_object());
|
||||
|
||||
json_t *data_copy;
|
||||
if (data && json_is_object(data)) {
|
||||
data_copy = json_deep_copy(data);
|
||||
} else {
|
||||
data_copy = json_object();
|
||||
}
|
||||
json_object_set_new(root, "data", data_copy);
|
||||
|
||||
rc = send_json_line(api, root);
|
||||
if (rc != MP_API_OK) {
|
||||
@@ -214,6 +233,7 @@ int mp_api_list(MultiplayerApi *api, json_t **out_list)
|
||||
json_t *root = json_object();
|
||||
if (!root) return MP_API_ERR_IO;
|
||||
|
||||
json_object_set_new(root, "identifier", json_string(api->identifier));
|
||||
json_object_set_new(root, "cmd", json_string("list"));
|
||||
|
||||
rc = send_json_line(api, root);
|
||||
@@ -276,7 +296,8 @@ int mp_api_join(MultiplayerApi *api,
|
||||
|
||||
json_t *root = json_object();
|
||||
if (!root) return MP_API_ERR_IO;
|
||||
|
||||
|
||||
json_object_set_new(root, "identifier", json_string(api->identifier));
|
||||
json_object_set_new(root, "session", json_string(sessionId));
|
||||
json_object_set_new(root, "cmd", json_string("join"));
|
||||
|
||||
@@ -371,16 +392,20 @@ int mp_api_join(MultiplayerApi *api,
|
||||
return joinAccepted ? MP_API_OK : MP_API_ERR_REJECTED;
|
||||
}
|
||||
|
||||
int mp_api_game(MultiplayerApi *api, json_t *data) {
|
||||
int mp_api_game(MultiplayerApi *api, json_t *data, const char* destination) {
|
||||
if (!api || !data) return MP_API_ERR_ARGUMENT;
|
||||
if (api->sockfd < 0 || !api->session_id) return MP_API_ERR_STATE;
|
||||
|
||||
json_t *root = json_object();
|
||||
if (!root) return MP_API_ERR_IO;
|
||||
|
||||
json_object_set_new(root, "identifier", json_string(api->identifier));
|
||||
json_object_set_new(root, "session", json_string(api->session_id));
|
||||
json_object_set_new(root, "cmd", json_string("game"));
|
||||
|
||||
if(destination)
|
||||
json_object_set_new(root, "destination", json_string(destination));
|
||||
|
||||
json_t *data_copy;
|
||||
if (json_is_object(data)) {
|
||||
data_copy = json_deep_copy(data);
|
||||
@@ -394,14 +419,14 @@ int mp_api_game(MultiplayerApi *api, json_t *data) {
|
||||
|
||||
int mp_api_listen(MultiplayerApi *api,
|
||||
MultiplayerListener cb,
|
||||
void *user_data) {
|
||||
void *context) {
|
||||
if (!api || !cb) return -1;
|
||||
|
||||
ListenerNode *node = (ListenerNode *)malloc(sizeof(ListenerNode));
|
||||
if (!node) return -1;
|
||||
|
||||
node->cb = cb;
|
||||
node->user_data = user_data;
|
||||
node->context = context;
|
||||
|
||||
pthread_mutex_lock(&api->lock);
|
||||
node->id = api->next_listener_id++;
|
||||
@@ -505,6 +530,8 @@ static int send_json_line(MultiplayerApi *api, json_t *obj) {
|
||||
return MP_API_ERR_IO;
|
||||
}
|
||||
|
||||
printf("Sending JSON: %s\n", text); // Debug print
|
||||
|
||||
size_t len = strlen(text);
|
||||
int fd = api->sockfd;
|
||||
|
||||
@@ -640,7 +667,7 @@ static void process_line(MultiplayerApi *api, const char *line) {
|
||||
while (node) {
|
||||
if (node->cb) {
|
||||
snapshot[idx].cb = node->cb;
|
||||
snapshot[idx].user_data = node->user_data;
|
||||
snapshot[idx].context = node->context;
|
||||
idx++;
|
||||
}
|
||||
node = node->next;
|
||||
@@ -648,7 +675,7 @@ static void process_line(MultiplayerApi *api, const char *line) {
|
||||
pthread_mutex_unlock(&api->lock);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
snapshot[i].cb(cmd, (int64_t)msgId, clientId, data_obj, snapshot[i].user_data);
|
||||
snapshot[i].cb(cmd, (int64_t)msgId, clientId, data_obj, snapshot[i].context);
|
||||
}
|
||||
|
||||
free(snapshot);
|
||||
@@ -728,4 +755,4 @@ static int start_recv_thread(MultiplayerApi *api) {
|
||||
|
||||
api->recv_thread_started = 1;
|
||||
return MP_API_OK;
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,6 @@
|
||||
#include <stdint.h>
|
||||
#include "jansson/jansson.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct MultiplayerApi MultiplayerApi;
|
||||
|
||||
/* Callback‑typ för inkommande events från servern. */
|
||||
@@ -16,7 +12,7 @@ typedef void (*MultiplayerListener)(
|
||||
int64_t messageId, /* sekventiellt meddelande‑ID (från host) */
|
||||
const char *clientId, /* avsändarens klient‑ID (eller NULL) */
|
||||
json_t *data, /* JSON‑objekt med godtycklig speldata */
|
||||
void *user_data /* godtycklig pekare som skickas vidare */
|
||||
void *context /* godtycklig pekare som skickas vidare */
|
||||
);
|
||||
|
||||
/* Returkoder */
|
||||
@@ -31,7 +27,7 @@ enum {
|
||||
};
|
||||
|
||||
/* Skapar en ny API‑instans. Returnerar NULL vid fel. */
|
||||
MultiplayerApi *mp_api_create(const char *server_host, uint16_t server_port);
|
||||
MultiplayerApi *mp_api_create(const char *server_host, uint16_t server_port, const char *identifier);
|
||||
|
||||
/* Stänger ner anslutning, stoppar mottagartråd och frigör minne. */
|
||||
void mp_api_destroy(MultiplayerApi *api);
|
||||
@@ -41,9 +37,10 @@ void mp_api_destroy(MultiplayerApi *api);
|
||||
anroparen ansvarar för att free:a. out_data (om ej NULL) får ett json_t*
|
||||
med extra data från servern (anroparen ska json_decref när klart). */
|
||||
int mp_api_host(MultiplayerApi *api,
|
||||
char **out_session,
|
||||
char **out_clientId,
|
||||
json_t **out_data);
|
||||
json_t *data,
|
||||
char **out_session,
|
||||
char **out_clientId,
|
||||
json_t **out_data);
|
||||
|
||||
/*
|
||||
Hämtar en lista över tillgängliga publika sessioner.
|
||||
@@ -70,19 +67,15 @@ int mp_api_join(MultiplayerApi *api,
|
||||
json_t **out_data);
|
||||
|
||||
/* Skickar ett "game"‑meddelande med godtycklig JSON‑data till sessionen. */
|
||||
int mp_api_game(MultiplayerApi *api, json_t *data);
|
||||
int mp_api_game(MultiplayerApi *api, json_t *data, const char* destination);
|
||||
|
||||
/* Registrerar en lyssnare för inkommande events.
|
||||
Returnerar ett positivt listener‑ID, eller −1 vid fel. */
|
||||
int mp_api_listen(MultiplayerApi *api,
|
||||
MultiplayerListener cb,
|
||||
void *user_data);
|
||||
void *context);
|
||||
|
||||
/* Avregistrerar lyssnare. Listener‑ID är värdet från mp_api_listen. */
|
||||
void mp_api_unlisten(MultiplayerApi *api, int listener_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MULTIPLAYER_API_H */
|
||||
#endif /* MULTIPLAYER_API_H */
|
||||
104
src/session/networking.c
Normal file
104
src/session/networking.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "networking.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define ONVO_IDENTIFIER "c2438167-831b-4bf7-8bdc-abcdefabcd00"
|
||||
|
||||
static inline bool setup_api(Game_Networking *networking) {
|
||||
assert(networking != NULL);
|
||||
|
||||
if(networking->api != NULL) {
|
||||
printf("Failed to set up API. Already active.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
MultiplayerApi *mp_api = mp_api_create("kontoret.onvo.se", 9001, ONVO_IDENTIFIER);
|
||||
if(mp_api == NULL) {
|
||||
printf("Failed to set up API. Could not initialize.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
networking->api = mp_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool networking_try_host(Game_Networking *networking, Game_Session *session, Game_Session_Settings settings) {
|
||||
assert(networking != NULL);
|
||||
|
||||
if(!settings.online) {
|
||||
printf("Failed to host; Game_Session_Settings.online == false, expected it to be true.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!setup_api(networking)) {
|
||||
printf("Failed to host; API is already set up.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char *session_id = NULL;
|
||||
char *local_client_id = NULL;
|
||||
json_t *response_data = NULL;
|
||||
int host_result = mp_api_host(
|
||||
networking->api,
|
||||
NULL, // TODO: SS - Send data to server that contains the game-session's settings.
|
||||
&session_id,
|
||||
&local_client_id,
|
||||
&response_data
|
||||
);
|
||||
if(host_result != MP_API_OK) {
|
||||
printf("Failed to host; Got result: %i.\n", host_result);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Started hosting session '%s', local_client_id is '%s'.\n", session_id, local_client_id);
|
||||
networking->session_id = session_id;
|
||||
networking->local_client_id = local_client_id;
|
||||
|
||||
// TODO: SS - Start listening.
|
||||
|
||||
// Set up session.
|
||||
game_session_init(
|
||||
session,
|
||||
settings
|
||||
);
|
||||
|
||||
if(response_data != NULL) {
|
||||
// TODO: SS - Handle JSON-response.
|
||||
json_decref(response_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool networking_try_join(Game_Networking *networking, const char *session_id) {
|
||||
assert(networking != NULL);
|
||||
|
||||
if(!setup_api(networking)) {
|
||||
printf("Failed to join; API is already set up.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Trying to join session with id: '%s' ...\n", session_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool networking_stop_hosting(Game_Networking *networking) {
|
||||
assert(networking != NULL);
|
||||
if(networking->api == NULL) {
|
||||
printf("Failed to stop hosting; API is not set up.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_api_destroy(networking->api);
|
||||
networking->api = NULL;
|
||||
|
||||
if(networking->session_id != NULL) {
|
||||
free(networking->session_id);
|
||||
}
|
||||
if(networking->local_client_id != NULL) {
|
||||
free(networking->local_client_id);
|
||||
}
|
||||
|
||||
printf("Stopped hosting.\n");
|
||||
return true;
|
||||
}
|
||||
19
src/session/networking.h
Normal file
19
src/session/networking.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef NETWORKING_H
|
||||
#define NETWORKING_H
|
||||
|
||||
#include "multiplayer_api.h"
|
||||
#include "game_session.h"
|
||||
|
||||
typedef struct {
|
||||
MultiplayerApi *api;
|
||||
|
||||
char *session_id;
|
||||
char *local_client_id;
|
||||
} Game_Networking;
|
||||
|
||||
bool networking_try_host(Game_Networking *networking, Game_Session *session, Game_Session_Settings settings);
|
||||
bool networking_try_join(Game_Networking *networking, const char *session_id);
|
||||
|
||||
bool networking_stop_hosting(Game_Networking *networking);
|
||||
|
||||
#endif
|
||||
@@ -25,6 +25,8 @@ void game_world_destroy(Game_World *world);
|
||||
bool game_world_create_entity(Game_World *world, Entity_Type type, uint16_t x, uint16_t y, Entity_ID *out_entity_id);
|
||||
void game_world_destroy_entity(Game_World *world, Entity_ID entity_id);
|
||||
|
||||
// TODO: SS - "void game_world_spawn_player(Game_World *world, ..)"
|
||||
|
||||
Entity *game_world_try_get_entity_by_id(Game_World *world, Entity_ID id);
|
||||
|
||||
#endif
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
#define SIM_COMMANDS_PER_PLAYER 4
|
||||
|
||||
Simulation_World simulation_create_world(uint32_t seed, uint8_t max_players, uint16_t width, uint16_t height) {
|
||||
Simulation_World simulation_create_world(uint32_t seed, bool online, uint8_t max_players, uint16_t width, uint16_t height) {
|
||||
Simulation_World w;
|
||||
memset(&w, 0, sizeof(Simulation_World));
|
||||
|
||||
w.tick = 0;
|
||||
|
||||
w.online = online;
|
||||
|
||||
w.game_world = game_world_create(seed, width, height);
|
||||
assert(w.game_world != NULL);
|
||||
|
||||
@@ -97,9 +99,7 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
||||
|
||||
switch(simulation_world->match_state) {
|
||||
case Simulation_Match_State_Waiting_To_Start: {
|
||||
bool is_singleplayer = simulation_world->max_players == 1;
|
||||
|
||||
if(is_singleplayer) {
|
||||
if(!simulation_world->online) { // If not online, just go to Counting_Down.
|
||||
simulation_world->match_state = Simulation_Match_State_Counting_Down;
|
||||
}
|
||||
else {
|
||||
@@ -230,7 +230,6 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
||||
|
||||
// Figure out what cell we're on and what cell we want to go to.
|
||||
Grid_Cell *current_cell = grid_get_cell(&gw->grid, entity->x, entity->y);
|
||||
Grid_Cell *start_cell = current_cell;
|
||||
assert(current_cell != NULL);
|
||||
Grid_Cell *target_cell = grid_get_cell(&gw->grid, entity->x + dx, entity->y + dy);
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#define SIMULATION_WORLD_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "shared/game_world.h"
|
||||
#include "shared/random.h" // Deterministic random.
|
||||
#include "player.h"
|
||||
#include "command.h"
|
||||
|
||||
@@ -17,6 +19,8 @@ typedef enum {
|
||||
typedef struct {
|
||||
uint64_t tick;
|
||||
|
||||
bool online;
|
||||
|
||||
Game_World *game_world;
|
||||
|
||||
Simulation_Match_State match_state;
|
||||
@@ -29,7 +33,7 @@ typedef struct {
|
||||
uint16_t max_commands;
|
||||
} Simulation_World;
|
||||
|
||||
Simulation_World simulation_create_world(uint32_t seed, uint8_t max_players, uint16_t width, uint16_t height);
|
||||
Simulation_World simulation_create_world(uint32_t seed, bool online, uint8_t max_players, uint16_t width, uint16_t height);
|
||||
void simulation_destroy_world(Simulation_World *simulation_world);
|
||||
|
||||
void simulation_world_tick(Simulation_World *simulation_world);
|
||||
|
||||
Reference in New Issue
Block a user