HamsterNet pre-alpha

Moros Smith 3 months ago
parent 0f725d2403
commit 1a1a92e02a
  1. 7
      CMakeLists.txt
  2. 295
      src/HamsterNet.cpp
  3. 46
      src/HamsterNet.h
  4. 24765
      src/json.hpp

@ -246,6 +246,8 @@ if (EMSCRIPTEN)
-sMIN_WEBGL_VERSION=2 -sMIN_WEBGL_VERSION=2
-sUSE_LIBPNG=1 -sUSE_LIBPNG=1
-sLLD_REPORT_UNDEFINED -sLLD_REPORT_UNDEFINED
-s ASYNCIFY
-sASYNCIFY_IMPORTS=hamsterNet__initSession,hamsterNet__setRacerName,hamsterNet__startRace,hamsterNet__finishRace,hamsterNet__getLeaderboard
--preload-file ${SOURCE_DATA_DIR}@assets) --preload-file ${SOURCE_DATA_DIR}@assets)
else() else()
target_link_options( target_link_options(
@ -255,7 +257,10 @@ if (EMSCRIPTEN)
-sMAX_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2
-sMIN_WEBGL_VERSION=2 -sMIN_WEBGL_VERSION=2
-sUSE_LIBPNG=1 -sUSE_LIBPNG=1
-sLLD_REPORT_UNDEFINED) -sLLD_REPORT_UNDEFINED
-s ASYNCIFY
-sASYNCIFY_IMPORTS=hamsterNet__initSession,hamsterNet__setRacerName,hamsterNet__startRace,hamsterNet__finishRace,hamsterNet__getLeaderboard
)
endif() endif()
set_target_properties(${OutputExecutable} PROPERTIES LINK_FLAGS "--shell-file ${CMAKE_CURRENT_SOURCE_DIR}/emscripten_shell.html") set_target_properties(${OutputExecutable} PROPERTIES LINK_FLAGS "--shell-file ${CMAKE_CURRENT_SOURCE_DIR}/emscripten_shell.html")

@ -0,0 +1,295 @@
#include <HamsterNet.h>
#include <json.hpp>
#ifdef __EMSCRIPTEN__
EM_JS(int, hamsterNet__initSession, (), {
return Asyncify.handleSleep(function(wakeUp) {
fetch('/session', { method: 'POST', credentials: 'same-origin' })
.then((response) =>
{
return response.ok
? response.json().then((data) => JSON.stringify(data, null, 2))
: Promise.reject(new Error("Unexpected response"));
})
.then((message) =>
{
console.log(message);
wakeUp(1);
})
.catch((err) =>
{
console.error(err.message);
wakeUp(0);
})
});
});
EM_JS(int, hamsterNet__setRacerName, (const char* str), {
let racerName = UTF8ToString(str);
return Asyncify.handleSleep(function(wakeUp) {
fetch('/name', {
method: 'POST',
credentials: 'same-origin',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ userName: racerName })
}).then((response) =>
{
return response.ok
? response.json().then((data) => JSON.stringify(data, null, 2))
: Promise.reject(new Error("Unexpected response"));
})
.then((message) =>
{
wakeUp(1);
})
.catch((err) =>
{
console.error(err.message);
wakeUp(0);
})
});
});
EM_JS(int, hamsterNet__startRace, (), {
return Asyncify.handleSleep(function(wakeUp) {
fetch('/race', {
method: 'POST',
credentials: 'same-origin',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({})
}).then((response) =>
{
return response.ok
? response.json()
: Promise.reject(new Error("Unexpected response"));
})
.then((message) =>
{
Module.hamsterRaceId = message.raceId;
wakeUp(1);
})
.catch((err) =>
{
console.error(err.message);
wakeUp(0);
})
});
});
EM_JS(int, hamsterNet__finishRace, (const char* raceMap, const char* raceColor, int raceTime), {
if(Module.hamsterRaceId === undefined)
{
console.error("Trying to finish a race that never start!");
return 0;
}
const raceData = {
raceId: Module.hamsterRaceId,
raceTime: raceTime,
raceMap: UTF8ToString(raceMap),
raceColor: UTF8ToString(raceColor),
};
return Asyncify.handleSleep(function(wakeUp) {
fetch('/race', {
method: 'PATCH',
credentials: 'same-origin',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(raceData)
}).then((response) =>
{
return response.ok
? response.json().then((data) => JSON.stringify(data, null, 2))
: Promise.reject(new Error("Unexpected response"));
})
.then((message) =>
{
wakeUp(1);
})
.catch((err) =>
{
console.error(err.message);
wakeUp(0);
})
});
});
EM_JS(int, hamsterNet__getLeaderboard, (const char* map, const char* sortBy, const int offset, const int limit, const int ascending), {
return Asyncify.handleSleep(function(wakeUp) {
// just some rudimentary input validation
const params = {
sort: ((ascending == 1) ? "asc" : "desc"),
map: encodeURIComponent(UTF8ToString(map)),
offset: offset,
limit: limit,
sortBy: "id"
};
if(['id', 'color', 'map', 'time', 'created_at'].indexOf(UTF8ToString(sortBy)) !== -1)
{
params.sortBy = UTF8ToString(sortBy);
}
fetch(`/race?map=${params.map}&sortBy=${params.sortBy}&sort=${params.sort}&offset=${params.offset}&limit=${params.limit}`, {
method: 'GET',
credentials: 'same-origin',
}).then((response) =>
{
return response.ok
? response.json()
: Promise.reject(new Error("Unexpected response"));
})
.then((message) =>
{
// set aside the results, so we can use them in the next phase.
Module._leaderboardResults = JSON.stringify(message.results);
wakeUp(1);
})
.catch((err) =>
{
console.error(err.message);
wakeUp(0);
});
});
});
#else
extern "C"
{
int hamsterNet__initSession()
{
std::cout << "hamsterNet__initSession is not implemented on this platform, artificially succeeding.\n";
return 1;
}
int hamsterNet__setRacerName(const char* str)
{
std::cout << "hamsterNet__setRacerName is not implemented on this platform, artificially succeeding.\n";
return 1;
}
int hamsterNet__startRace()
{
std::cout << "hamsterNet__startRace is not implemented on this platform, artificially succeeding.\n";
return 1;
}
int hamsterNet__finishRace(const char* raceMap, const char* raceColor, int raceTime)
{
std::cout << "hamsterNet__finishRace is not implemented on this platform, artificially succeeding.\n";
return 1;
}
int hamsterNet__getLeaderboard(const char *map, const char *sortBy, int offset, int limit, int ascending)
{
std::cout << "hamsterNet__getLeaderboard is not implemented on this platform, artificially succeeding.\n";
return 1;
}
}
#endif
HamsterNet::HamsterNet()
{ }
bool HamsterNet::InitSession()
{
return (hamsterNet__initSession() == 1);
}
void HamsterNet::SetColor(const std::string& hamsterColor)
{
m_color = hamsterColor;
}
bool HamsterNet::SetName(const std::string& name)
{
m_name = name;
return (hamsterNet__setRacerName(m_name.c_str()) == 1);
}
bool HamsterNet::StartRace(const std::string& map)
{
m_map = map;
m_tp1 = std::chrono::system_clock::now();
m_tp2 = std::chrono::system_clock::now();
return (hamsterNet__startRace() == 1);
}
bool HamsterNet::FinishRace()
{
m_tp2 = std::chrono::system_clock::now();
std::chrono::duration<double, std::milli> duration = m_tp2 - m_tp1;
m_time = static_cast<int>(duration.count());
return (hamsterNet__finishRace(m_map.c_str(), m_color.c_str(), m_time) == 1);
}
std::vector<LeaderboardEntry> HamsterNet::GetLeaderboard(const std::string& map, const int offset, const int limit, const std::string& sortBy, bool ascending)
{
std::vector<LeaderboardEntry> leaderboard;
int result = hamsterNet__getLeaderboard(map.c_str(), sortBy.c_str(), offset, limit, (ascending) ? 1 : 0);
if(result == 1)
{
#ifdef __EMSCRIPTEN__
char* leaderboardJsonString = (char*)EM_ASM_PTR({
// get the number of bytes we need to allocate to fit the string
let lengthBytes = lengthBytesUTF8(Module._leaderboardResults) + 1;
// allocate enough memory to hold the string
let stringOnWasmHeap = _malloc(lengthBytes);
// copy the javascript string into the heap
stringToUTF8(Module._leaderboardResults, stringOnWasmHeap, lengthBytes);
// we're done with this, remove it!
delete Module._leaderboardResults;
// return the pointer
return stringOnWasmHeap;
});
using json = nlohmann::json;
json leaderboardJson = json::parse(leaderboardJsonString);
free(leaderboardJsonString);
for(auto &el : leaderboardJson.items())
{
// std::string color;
// std::string name;
// std::string map;
// int time;
leaderboard.push_back(LeaderboardEntry{
el.value().at("color"),
el.value().at("name"),
el.value().at("map"),
el.value().at("time"),
});
}
std::cout << "get leaderboard successful\n";
#else
std::cout << "HamsterNet::GetLeaderboard is not implemented for this platform\n"
#endif
}
return leaderboard;
}

@ -0,0 +1,46 @@
#pragma once
#ifndef HAMSTER_NET_H
#define HAMSTER_NET_H
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#endif
#include <chrono>
#include <iostream>
#include <string>
#include <vector>
struct LeaderboardEntry {
std::string color;
std::string name;
std::string map;
int time;
};
class HamsterNet
{
public:
HamsterNet();
bool InitSession();
void SetColor(const std::string& color);
bool SetName(const std::string& name);
bool StartRace(const std::string& map);
bool FinishRace();
std::vector<LeaderboardEntry> GetLeaderboard(const std::string& map, const int offset = 0, const int limit = 100, const std::string& sortBy = "time", bool ascending = true);
private:
std::chrono::time_point<std::chrono::system_clock> m_tp1, m_tp2;
std::string m_color;
std::string m_name;
std::string m_map;
int m_time;
std::string raceId;
};
#endif // HAMSTER_NET_H

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save