Skip to content

Commit

Permalink
Merge pull request #20 from HeatXD/C-API
Browse files Browse the repository at this point in the history
C-API Overhaul

created a front facade now only gekkonet.h is needed to have access to all the needed functions.
  • Loading branch information
HeatXD authored Oct 28, 2024
2 parents c9e1439 + e06bf2c commit 56d8814
Show file tree
Hide file tree
Showing 26 changed files with 860 additions and 584 deletions.
195 changes: 119 additions & 76 deletions Examples/FakeOnlineSession/FakeOnlineSession.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#include <iostream>
#include "SDL2/SDL.h"
#include "gekko.h"
#include <chrono>
#include <vector>

#include "SDL2/SDL.h"

#define GEKKONET_STATIC

#include "gekkonet.h"

SDL_Window* window1 = nullptr;
SDL_Window* window2 = nullptr;
Expand Down Expand Up @@ -115,13 +120,13 @@ struct GState {
int desync_test = 0; // changing this value for each state can trigger the desync system
};

void save_state(GState* gs, Gekko::GameEvent* ev) {
void save_state(GState* gs, GekkoGameEvent* ev) {
*ev->data.save.state_len = sizeof(GState);
*ev->data.save.checksum = fletcher32((uint16_t*)gs, sizeof(GState));
std::memcpy(ev->data.save.state, gs, sizeof(GState));
}

void load_state(GState* gs, Gekko::GameEvent* ev) {
void load_state(GState* gs, GekkoGameEvent* ev) {
std::memcpy(gs, ev->data.load.state, sizeof(GState));
}

Expand Down Expand Up @@ -179,44 +184,54 @@ void get_key_inputs(GInput inputs[4]) {
inputs[3].input.dir.right = keys[SDL_SCANCODE_L];
}

class FakeNetAdapter : public Gekko::NetAdapter {
int recv_idx = 0;
std::vector<std::unique_ptr<Gekko::NetResult>> inbox_session1;
std::vector<std::unique_ptr<Gekko::NetResult>> inbox_session2;

virtual std::vector<std::unique_ptr<Gekko::NetResult>> ReceiveData() {
auto& curr_inbox = recv_idx % 2 == 1 ? inbox_session2 : inbox_session1;
auto result = std::vector<std::unique_ptr<Gekko::NetResult>>();

for (auto& ptr : curr_inbox) {
result.push_back(std::move(ptr));
}

curr_inbox.clear();
int recv_idx = 0;
std::vector<GekkoNetResult*> inbox_session1;
std::vector<GekkoNetResult*> inbox_session2;
std::vector<GekkoNetResult*> outbox;

static void fake_send_data(GekkoNetAddress* addr, const char* data, int length) {
// gekkonet will clean this up
auto result = new GekkoNetResult();

auto addr_to = *(unsigned char*)addr->data;
auto addr_from = addr_to == 1 ? 2 : 1;
// gekkonet will clean this up
result->addr.data = new unsigned char;
result->addr.size = sizeof(char);
std::memcpy(result->addr.data, &addr_from, result->addr.size);

// user created memory
// gekkonet will clean this up
result->data = new char[length];
std::memcpy(result->data, data, length);

result->data_len = length;

if (addr_from == 1) {
inbox_session2.push_back(result);
} else {
inbox_session1.push_back(result);
}
}

recv_idx++;
return result;
}
static void fake_free_data(void* data_ptr) {
// delete user created data
delete data_ptr;
}

virtual void SendData(Gekko::NetAddress& addr, const char* data, int length) {
auto result = std::make_unique<Gekko::NetResult>();
static GekkoNetResult** fake_receive_data(int* length) {
outbox.clear();

Gekko::u8 addr_from = (Gekko::u8)*addr.GetAddress() == 1 ? 2 : 1;
auto tmp = Gekko::NetAddress(&addr_from, (Gekko::u32)sizeof(char));
result->addr.Copy(&tmp);
auto& curr_inbox = recv_idx % 2 == 1 ? inbox_session2 : inbox_session1;
outbox.insert(outbox.begin(), curr_inbox.begin(), curr_inbox.end());

result->data = std::unique_ptr<char[]>(new char[length]);
std::memcpy(result->data.get(), data, length);
*length = (int) curr_inbox.size();
curr_inbox.clear();

result->data_len = length;
recv_idx++;

if (addr_from == 1) {
inbox_session2.push_back(std::move(result));
} else {
inbox_session1.push_back(std::move(result));
}
}
};
return outbox.data();
}

int main(int argc, char* args[])
{
Expand All @@ -228,14 +243,21 @@ int main(int argc, char* args[])
// state2.desync_test = 11;
GInput inputs[4] = {};

auto adapter = FakeNetAdapter();
auto adapter = GekkoNetAdapter();

adapter.free_data = fake_free_data;
adapter.send_data = fake_send_data;
adapter.receive_data = fake_receive_data;

int num_players = 4;

auto sess1 = Gekko::Session();
auto sess2 = Gekko::Session();
GekkoSession* sess1 = nullptr;
GekkoSession* sess2 = nullptr;

auto conf = Gekko::Config();
gekko_create(&sess1);
gekko_create(&sess2);

auto conf = GekkoConfig();

conf.num_players = num_players;
conf.input_size = sizeof(int);
Expand All @@ -245,36 +267,38 @@ int main(int argc, char* args[])
conf.limited_saving = false;
conf.desync_detection = true;

sess1.Init(conf);
sess2.Init(conf);
gekko_start(sess1, &conf);
gekko_start(sess2, &conf);

sess1.SetNetAdapter(&adapter);
sess2.SetNetAdapter(&adapter);
gekko_net_adapter_set(sess1, &adapter);
gekko_net_adapter_set(sess2, &adapter);

char addrs1 = 1;
auto addr1 = Gekko::NetAddress(&addrs1, sizeof(char));
auto addr1 = GekkoNetAddress{ &addrs1, sizeof(char) };

char addrs2 = 2;
auto addr2 = Gekko::NetAddress(&addrs2, sizeof(char));
auto addr2 = GekkoNetAddress{ &addrs2, sizeof(char) };

// local and remote players are order dependant. spectators are not.
auto s1p1 = sess1.AddActor(Gekko::PlayerType::LocalPlayer);
auto s1p2 = sess1.AddActor(Gekko::PlayerType::RemotePlayer, &addr2);
auto s1p3 = sess1.AddActor(Gekko::PlayerType::LocalPlayer);
auto s1p4 = sess1.AddActor(Gekko::PlayerType::RemotePlayer, &addr2);
sess1.SetLocalDelay(s1p1, 1);
sess1.SetLocalDelay(s1p3, 1);

auto s2p1 = sess2.AddActor(Gekko::PlayerType::RemotePlayer, &addr1);
auto s2p2 = sess2.AddActor(Gekko::PlayerType::LocalPlayer);
auto s2p3 = sess2.AddActor(Gekko::PlayerType::RemotePlayer, &addr1);
auto s2p4 = sess2.AddActor(Gekko::PlayerType::LocalPlayer);
sess2.SetLocalDelay(s2p2, 1);
sess2.SetLocalDelay(s2p4, 1);
int s1p1 = gekko_add_actor(sess1, GekkoPlayerType::LocalPlayer, nullptr);
int s1p2 = gekko_add_actor(sess1, GekkoPlayerType::RemotePlayer, &addr2);
int s1p3 = gekko_add_actor(sess1, GekkoPlayerType::LocalPlayer, nullptr);
int s1p4 = gekko_add_actor(sess1, GekkoPlayerType::RemotePlayer, &addr2);

gekko_set_local_delay(sess1, s1p1, 1);
gekko_set_local_delay(sess1, s1p3, 1);

int s2p1 = gekko_add_actor(sess2, GekkoPlayerType::RemotePlayer, &addr1);
int s2p2 = gekko_add_actor(sess2, GekkoPlayerType::LocalPlayer, nullptr);
int s2p3 = gekko_add_actor(sess2, GekkoPlayerType::RemotePlayer, &addr1);
int s2p4 = gekko_add_actor(sess2, GekkoPlayerType::LocalPlayer, nullptr);

gekko_set_local_delay(sess2, s2p2, 1);
gekko_set_local_delay(sess2, s2p4, 1);

// timing
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
using frame = std::chrono::duration<Gekko::u32, std::ratio<1, 60>>;
using frame = std::chrono::duration<unsigned int, std::ratio<1, 60>>;
using clock = std::chrono::steady_clock;

time_point timer(clock::now());
Expand All @@ -293,34 +317,41 @@ int main(int argc, char* args[])
get_key_inputs(inputs);

// add local inputs to the session
sess1.AddLocalInput(s1p1, &inputs[0].input.value);
sess2.AddLocalInput(s2p2, &inputs[1].input.value);
sess1.AddLocalInput(s1p3, &inputs[2].input.value);
sess2.AddLocalInput(s2p4, &inputs[3].input.value);
gekko_add_local_input(sess1, s1p1, &inputs[0].input.value);
gekko_add_local_input(sess2, s2p2, &inputs[1].input.value);
gekko_add_local_input(sess1, s1p3, &inputs[2].input.value);
gekko_add_local_input(sess2, s2p4, &inputs[3].input.value);

int frame = 0;

for (auto event : sess1.Events()) {
int count = 0;
auto events = gekko_session_events(sess1, &count);
for (int i = 0; i < count; i++) {
auto event = events[i];
printf("S1 EV: %d\n", event->type);
if (event->type == Gekko::DesyncDetected) {
if (event->type == DesyncDetected) {
auto desync = event->data.desynced;
printf("desync detected, f:%d, rh:%d, lc:%u, rc:%u\n", desync.frame, desync.remote_handle, desync.local_checksum, desync.remote_checksum);
}
}

for (auto ev : sess1.UpdateSession())
count = 0;
auto updates = gekko_update_session(sess1, &count);
for (int i = 0; i < count; i++)
{
auto ev = updates[i];

switch (ev->type)
{
case Gekko::SaveEvent:
case SaveEvent:
printf("S1 Save frame:%d\n", ev->data.save.frame);
save_state(&state1, ev);
break;
case Gekko::LoadEvent:
case LoadEvent:
printf("S1 Load frame:%d\n", ev->data.load.frame);
load_state(&state1, ev);
break;
case Gekko::AdvanceEvent:
case AdvanceEvent:
// on advance event, advance the gamestate using the given inputs
inputs[0].input.value = ev->data.adv.inputs[0];
inputs[1].input.value = ev->data.adv.inputs[4];
Expand All @@ -337,27 +368,35 @@ int main(int argc, char* args[])
}
}

for (auto event : sess2.Events()) {
count = 0;
events = gekko_session_events(sess2, &count);
for (int i = 0; i < count; i++) {
auto event = events[i];
printf("S2 EV: %d\n", event->type);
if (event->type == Gekko::DesyncDetected) {
if (event->type == DesyncDetected) {
auto desync = event->data.desynced;
printf("desync detected, f:%d, rh:%d, lc:%u, rc:%u\n", desync.frame, desync.remote_handle, desync.local_checksum, desync.remote_checksum);
}
}

for (auto ev : sess2.UpdateSession())

count = 0;
updates = gekko_update_session(sess2, &count);
for (int i = 0; i < count; i++)
{
auto ev = updates[i];

switch (ev->type)
{
case Gekko::SaveEvent:
case SaveEvent:
printf("S2 Save frame:%d\n", ev->data.save.frame);
save_state(&state2, ev);
break;
case Gekko::LoadEvent:
case LoadEvent:
printf("S2 Load frame:%d\n", ev->data.load.frame);
load_state(&state2, ev);
break;
case Gekko::AdvanceEvent:
case AdvanceEvent:
// on advance event, advance the gamestate using the given inputs
inputs[0].input.value = ev->data.adv.inputs[0];
inputs[1].input.value = ev->data.adv.inputs[4];
Expand Down Expand Up @@ -389,6 +428,10 @@ int main(int argc, char* args[])
SDL_RenderPresent(renderer1);
SDL_RenderPresent(renderer2);
}

gekko_destroy(sess1);
gekko_destroy(sess2);

del_windows();

return 0;
Expand Down
4 changes: 2 additions & 2 deletions Examples/FakeOnlineSession/FakeOnlineSession.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(VcpkgML)\SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(VcpkgML)\SDL2main.lib;msvcrtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
Expand All @@ -138,7 +138,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(VcpkgML)\SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(VcpkgML)\SDL2main.lib;msvcrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
Expand Down
Loading

0 comments on commit 56d8814

Please sign in to comment.