mirror of
https://github.com/sigonasr2/hamster.git
synced 2025-04-18 06:39:39 -05:00
Merge pull request #19 from sigonasr2/HamsterNet-pre-alpha
Hamster net pre alpha
This commit is contained in:
commit
c57ef6e498
@ -246,6 +246,8 @@ if (EMSCRIPTEN)
|
||||
-sMIN_WEBGL_VERSION=2
|
||||
-sUSE_LIBPNG=1
|
||||
-sLLD_REPORT_UNDEFINED
|
||||
-s ASYNCIFY
|
||||
-sASYNCIFY_IMPORTS=hamsterNet__initSession,hamsterNet__setRacerName,hamsterNet__startRace,hamsterNet__finishRace,hamsterNet__getLeaderboard
|
||||
--preload-file ${SOURCE_DATA_DIR}@assets)
|
||||
else()
|
||||
target_link_options(
|
||||
@ -255,7 +257,10 @@ if (EMSCRIPTEN)
|
||||
-sMAX_WEBGL_VERSION=2
|
||||
-sMIN_WEBGL_VERSION=2
|
||||
-sUSE_LIBPNG=1
|
||||
-sLLD_REPORT_UNDEFINED)
|
||||
-sLLD_REPORT_UNDEFINED
|
||||
-s ASYNCIFY
|
||||
-sASYNCIFY_IMPORTS=hamsterNet__initSession,hamsterNet__setRacerName,hamsterNet__startRace,hamsterNet__finishRace,hamsterNet__getLeaderboard
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(${OutputExecutable} PROPERTIES LINK_FLAGS "--shell-file ${CMAKE_CURRENT_SOURCE_DIR}/emscripten_shell.html")
|
||||
|
@ -40,30 +40,6 @@
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#output {
|
||||
position: fixed;
|
||||
display: none;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
width: 100%;
|
||||
height: 15vh;
|
||||
top:85vh;
|
||||
bottom: 0;
|
||||
margin-left: 1rem;
|
||||
padding-left: 1rem;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#container.show-console {
|
||||
bottom: 15vh;
|
||||
}
|
||||
|
||||
#output.show-console {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
display: block;
|
||||
border: 0px none;
|
||||
@ -75,12 +51,6 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#toggle-console {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -88,16 +58,12 @@
|
||||
<div id="container">
|
||||
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
|
||||
</div>
|
||||
<button id="toggle-console">Toggle Console</button>
|
||||
<script type='text/javascript'>
|
||||
var Module = {
|
||||
print: (function () {
|
||||
return (...args) => {
|
||||
var text = args.join(' ');
|
||||
window.parent.postMessage({
|
||||
message: "console-output",
|
||||
data: text + "\n",
|
||||
}, "*");
|
||||
console.log(text);
|
||||
};
|
||||
})(),
|
||||
canvas: (() => {
|
||||
@ -116,31 +82,6 @@
|
||||
monitorRunDependencies: (left) => {
|
||||
}
|
||||
};
|
||||
|
||||
window.onerror = (event) =>
|
||||
{
|
||||
window.parent.postMessage({
|
||||
message: "player-runtime-error",
|
||||
}, "*");
|
||||
};
|
||||
|
||||
window.parent.postMessage({
|
||||
message: "player-ready",
|
||||
}, "*");
|
||||
|
||||
window.addEventListener("message", (event) =>
|
||||
{
|
||||
if (typeof event.data !== "object")
|
||||
return;
|
||||
|
||||
if (typeof event.data.message !== "string")
|
||||
return;
|
||||
|
||||
if (event.data.message === "set-theme") {
|
||||
document.querySelector("body").className = event.data.theme;
|
||||
return;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
|
295
src/HamsterNet.cpp
Normal file
295
src/HamsterNet.cpp
Normal file
@ -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;
|
||||
}
|
46
src/HamsterNet.h
Normal file
46
src/HamsterNet.h
Normal file
@ -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
|
24765
src/json.hpp
Normal file
24765
src/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user