Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,642 @@
|
||||
#include "rapidjson/document.h"
|
||||
#include "scripts/binds.h"
|
||||
#include "threads.h"
|
||||
#include "main/references.h"
|
||||
#include "util/refcount.h"
|
||||
#include <curl/curl.h>
|
||||
#include <sstream>
|
||||
#include "str_util.h"
|
||||
#include "manager.h"
|
||||
#include "files.h"
|
||||
|
||||
#undef min
|
||||
|
||||
extern bool launchPatcher;
|
||||
|
||||
namespace scripts {
|
||||
|
||||
static const std::string WikiURI("http://wiki.starruler2.com/api.php?format=json&action=query&titles=$1&prop=revisions&rvprop=content");
|
||||
static const std::string APIURI("http://api.starruler2.com/$1");
|
||||
|
||||
static threads::threadreturn threadcall CurlThread(void*);
|
||||
static const std::string EMPTY_STRING("");
|
||||
struct WebData : AtomicRefCounted {
|
||||
CURL* curl;
|
||||
std::string uri;
|
||||
std::string result;
|
||||
volatile bool completed;
|
||||
std::string errorStr;
|
||||
std::function<void(WebData&)> onPerform;
|
||||
std::vector<std::pair<std::string,std::string>> postData;
|
||||
std::vector<std::pair<std::string,std::string>> headers;
|
||||
|
||||
WebData() : completed(true) {
|
||||
curl = curl_easy_init();
|
||||
}
|
||||
|
||||
~WebData() {
|
||||
while(!completed)
|
||||
threads::sleep(10);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void request(const std::string& URI, std::function<void(WebData&)> perf = nullptr) {
|
||||
if(!completed) {
|
||||
scripts::throwException("Attempting to request WebData result before request completed.");
|
||||
return;
|
||||
}
|
||||
|
||||
completed = false;
|
||||
onPerform = perf;
|
||||
uri = URI;
|
||||
threads::createThread(CurlThread, this);
|
||||
}
|
||||
|
||||
bool isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
bool wasError() {
|
||||
return errorStr.size() != 0;
|
||||
}
|
||||
|
||||
void addPost(const std::string& name, const std::string& value) {
|
||||
if(!completed)
|
||||
return;
|
||||
postData.push_back(std::pair<std::string,std::string>(name, value));
|
||||
}
|
||||
|
||||
void addHeader(const std::string& name, const std::string& value) {
|
||||
if(!completed)
|
||||
return;
|
||||
headers.push_back(std::pair<std::string,std::string>(name, value));
|
||||
}
|
||||
|
||||
const std::string& getResult() {
|
||||
if(!completed) {
|
||||
scripts::throwException("Attempting to get WebData result before request completed.");
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& getError() {
|
||||
if(!completed) {
|
||||
scripts::throwException("Attempting to get WebData error before request completed.");
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
return errorStr;
|
||||
}
|
||||
};
|
||||
|
||||
WebData* makeWebData() {
|
||||
return new WebData();
|
||||
}
|
||||
|
||||
static size_t curlOutput(void* data, size_t size, size_t nmemb, void* ptr) {
|
||||
if(!ptr)
|
||||
return size * nmemb;
|
||||
WebData& dat = *(WebData*)ptr;
|
||||
int sz = size * nmemb;
|
||||
dat.result.append((char*)data, sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static threads::threadreturn threadcall CurlThread(void* ptr) {
|
||||
WebData& dat = *(WebData*)ptr;
|
||||
if(dat.result.size() != 0)
|
||||
dat.result = "";
|
||||
|
||||
curl_httppost* formpost = nullptr;
|
||||
curl_httppost* lastptr = nullptr;
|
||||
struct curl_slist* headers = nullptr;
|
||||
|
||||
if(!dat.postData.empty()) {
|
||||
for(size_t i = 0, cnt = dat.postData.size(); i < cnt; ++i) {
|
||||
curl_formadd(&formpost, &lastptr,
|
||||
CURLFORM_COPYNAME, dat.postData[i].first.c_str(),
|
||||
CURLFORM_COPYCONTENTS, dat.postData[i].second.c_str(),
|
||||
CURLFORM_END);
|
||||
}
|
||||
dat.postData.clear();
|
||||
|
||||
curl_easy_setopt(dat.curl, CURLOPT_HTTPPOST, formpost);
|
||||
}
|
||||
|
||||
if(!dat.headers.empty()) {
|
||||
for(size_t i = 0, cnt = dat.headers.size(); i < cnt; ++i) {
|
||||
std::string str = dat.headers[i].first+": "+dat.headers[i].second;
|
||||
headers = curl_slist_append(headers, str.c_str());
|
||||
}
|
||||
dat.headers.clear();
|
||||
|
||||
curl_easy_setopt(dat.curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
|
||||
curl_easy_setopt(dat.curl, CURLOPT_URL, dat.uri.c_str());
|
||||
curl_easy_setopt(dat.curl, CURLOPT_WRITEFUNCTION, curlOutput);
|
||||
curl_easy_setopt(dat.curl, CURLOPT_WRITEHEADER, nullptr);
|
||||
curl_easy_setopt(dat.curl, CURLOPT_WRITEDATA, ptr);
|
||||
curl_easy_setopt(dat.curl, CURLOPT_FAILONERROR, 1);
|
||||
CURLcode err = curl_easy_perform(dat.curl);
|
||||
|
||||
if(err == CURLE_OK) {
|
||||
if(dat.errorStr.size() != 0)
|
||||
dat.errorStr = "";
|
||||
}
|
||||
else
|
||||
dat.errorStr = curl_easy_strerror(err);
|
||||
|
||||
if(dat.onPerform)
|
||||
dat.onPerform(dat);
|
||||
|
||||
if(formpost)
|
||||
curl_formfree(formpost);
|
||||
if(headers)
|
||||
curl_slist_free_all(headers);
|
||||
dat.completed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
threads::Mutex updateLock;
|
||||
threads::Signal isUpdating;
|
||||
double updateProgress = 0;
|
||||
int updateStatus = 0;
|
||||
|
||||
bool getIsUpdating() {
|
||||
return !isUpdating.check(0);
|
||||
}
|
||||
|
||||
struct MD5 {
|
||||
unsigned bytes[4];
|
||||
|
||||
MD5() : bytes() {
|
||||
}
|
||||
|
||||
static unsigned endianFlip(unsigned x) {
|
||||
return (x << 24) | (x >> 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
|
||||
}
|
||||
|
||||
void fromString(const std::string& str) {
|
||||
for(unsigned i = 0; i < 4; ++i) {
|
||||
std::stringstream s(str.substr(i*8, 8));
|
||||
s >> std::hex >> bytes[i];
|
||||
bytes[i] = endianFlip(bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream s;
|
||||
s.fill('0');
|
||||
s << std::hex;
|
||||
for(unsigned i = 0; i < 4; ++i) {
|
||||
s.width(8);
|
||||
s << endianFlip(bytes[i]);
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
bool zero() {
|
||||
return !bytes[0] && !bytes[1] && !bytes[2] && !bytes[3];
|
||||
}
|
||||
|
||||
bool operator==(const MD5& other) const {
|
||||
return bytes[0] == other.bytes[0] && bytes[1] == other.bytes[1] && bytes[2] == other.bytes[2] && bytes[3] == other.bytes[3];
|
||||
}
|
||||
};
|
||||
|
||||
unsigned rotLeft(unsigned value, unsigned shifts) {
|
||||
return (value << shifts) | (value >> (32-shifts));
|
||||
}
|
||||
|
||||
MD5 hash(const std::string& filename) {
|
||||
//Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
|
||||
const unsigned s[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };
|
||||
const unsigned K[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
|
||||
|
||||
MD5 md5;
|
||||
unsigned& a0 = md5.bytes[0];
|
||||
unsigned& b0 = md5.bytes[1];
|
||||
unsigned& c0 = md5.bytes[2];
|
||||
unsigned& d0 = md5.bytes[3];
|
||||
|
||||
FILE* file = fopen(filename.c_str(), "rb");
|
||||
if(!file)
|
||||
return md5;
|
||||
|
||||
a0 = 0x67452301;
|
||||
b0 = 0xefcdab89;
|
||||
c0 = 0x98badcfe;
|
||||
d0 = 0x10325476;
|
||||
|
||||
unsigned long long length = 0, pos = 0;
|
||||
unsigned chunk[16];
|
||||
|
||||
int end = 0;
|
||||
while(end != 2) {
|
||||
auto bytes = fread(chunk, 1, 16*4, file);
|
||||
length += bytes;
|
||||
if(bytes < 16 * 4) {
|
||||
if(end == 0) {
|
||||
memset((char*)chunk + bytes, 0, 16*4 - bytes);
|
||||
*((unsigned char*)chunk + bytes) = 0x80;
|
||||
end = 1;
|
||||
if(bytes < 14*4) {
|
||||
length *= 8;
|
||||
memcpy(chunk + 14, &length, sizeof(length));
|
||||
end = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(chunk, 0, sizeof(chunk));
|
||||
length *= 8;
|
||||
memcpy(chunk + 14, &length, sizeof(length));
|
||||
end = 2;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned A = a0, B = b0, C = c0, D = d0;
|
||||
for(unsigned i = 0; i < 64; ++i) {
|
||||
unsigned F, g;
|
||||
if(i < 16) {
|
||||
F = (B & C) | (~B & D);
|
||||
g = i;
|
||||
}
|
||||
else if(i < 32) {
|
||||
F = (D & B) | (~D & C);
|
||||
g = (i*5 + 1) % 16;
|
||||
}
|
||||
else if(i < 48) {
|
||||
F = B ^ C ^ D;
|
||||
g = (i * 3 + 5) % 16;
|
||||
}
|
||||
else {
|
||||
F = C ^ (B | ~D);
|
||||
g = (i * 7) % 16;
|
||||
}
|
||||
|
||||
unsigned newA = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = B + rotLeft(A + F + K[i] + chunk[g], s[i]);
|
||||
A = newA;
|
||||
}
|
||||
|
||||
a0 += A;
|
||||
b0 += B;
|
||||
c0 += C;
|
||||
d0 += D;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return md5;
|
||||
}
|
||||
|
||||
static int GameUpdate() {
|
||||
unsigned totalFiles = 0, downloaded = 0;
|
||||
const std::string profile = path_join(getProfileRoot(), "patch/");
|
||||
makeDirectory(profile);
|
||||
updateProgress = 0;
|
||||
WebData fileList;
|
||||
for(unsigned i = 0; i < 3; ++i) {
|
||||
fileList.request(format(APIURI.c_str(), "updates/latest"));
|
||||
|
||||
while(!fileList.completed)
|
||||
threads::sleep(1);
|
||||
|
||||
if(!fileList.wasError())
|
||||
break;
|
||||
}
|
||||
|
||||
if(fileList.wasError()) {
|
||||
updateProgress = 100.0;
|
||||
updateStatus = -1;
|
||||
isUpdating.signalDown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateProgress = 1.0;
|
||||
|
||||
std::unordered_map<std::string,MD5> files;
|
||||
|
||||
auto anyHash = hash("Star Ruler 2.exe");
|
||||
|
||||
int failures = 0;
|
||||
std::unordered_map<std::string,std::string> queuedDownloads;
|
||||
std::unordered_map<std::string,WebData*> activeDownloads;
|
||||
std::unordered_set<std::string> queuedDeletions;
|
||||
|
||||
auto checkDownloads = [&](bool beginDownloads) {
|
||||
for(auto dl = activeDownloads.begin(), dlend = activeDownloads.end(); dl != dlend; ++dl) {
|
||||
auto* web = dl->second;
|
||||
if(web->completed) {
|
||||
if(web->wasError()) {
|
||||
failures += 1;
|
||||
queuedDownloads[dl->first] = web->uri;
|
||||
delete dl->second;
|
||||
activeDownloads.erase(dl);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
auto patchName = profile + dl->first;
|
||||
if(FILE* file = fopen(patchName.c_str(), "wb")) {
|
||||
fwrite(dl->second->result.c_str(), 1, dl->second->result.size(), file);
|
||||
fclose(file);
|
||||
}
|
||||
downloaded += 1;
|
||||
delete dl->second;
|
||||
activeDownloads.erase(dl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(beginDownloads && activeDownloads.size() < 3 && !queuedDownloads.empty()) {
|
||||
auto f = queuedDownloads.begin();
|
||||
auto* web = new WebData();
|
||||
web->request(f->second);
|
||||
activeDownloads[f->first] = web;
|
||||
queuedDownloads.erase(f);
|
||||
}
|
||||
};
|
||||
|
||||
auto queueDownload = [&](const std::string& relpath, MD5 current, MD5 updated) {
|
||||
if(updated.zero()) {
|
||||
queuedDeletions.insert(relpath);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fileExists(profile + relpath)) {
|
||||
auto md5 = hash(profile + relpath);
|
||||
if(md5 == updated)
|
||||
return;
|
||||
remove((profile + relpath).c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::string> paths;
|
||||
path_split(relpath, paths);
|
||||
|
||||
std::string path = profile;
|
||||
for(unsigned i = 0, cnt = paths.size(); i + 1 < cnt; ++i) {
|
||||
path += paths[i] + "/";
|
||||
makeDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
totalFiles += 1;
|
||||
auto uri = format("http://api.starruler2.com/updates/$1/$2", current.toString(), updated.toString());
|
||||
queuedDownloads[relpath] = uri;
|
||||
checkDownloads(true);
|
||||
};
|
||||
|
||||
std::stringstream list(fileList.result);
|
||||
std::string line, key, value;
|
||||
//Line Format: relative_path<tab>md5_hash
|
||||
while(!list.eof()) {
|
||||
std::getline(list, line);
|
||||
if(!splitKeyValue(line, key, value, "\t"))
|
||||
continue;
|
||||
if(value.size() == 32) {
|
||||
MD5 md5;
|
||||
md5.fromString(value);
|
||||
files[key] = md5;
|
||||
}
|
||||
}
|
||||
|
||||
//Clear out any unnecessary files from the patch folder
|
||||
std::function<void(const std::string&)> clearFolder;
|
||||
clearFolder = [&](const std::string& relPath) {
|
||||
std::vector<std::string> listing;
|
||||
if(listDirectory(profile + relPath, listing)) {
|
||||
for(auto f = listing.begin(), fend = listing.end(); f != fend; ++f) {
|
||||
auto path = path_join(profile, *f);
|
||||
if(isDirectory(path)) {
|
||||
clearFolder(relPath + *f + "/");
|
||||
}
|
||||
else {
|
||||
auto fExists = files.find(relPath + *f);
|
||||
if(fExists == files.end() || fExists->second.zero())
|
||||
remove(path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
clearFolder("");
|
||||
|
||||
unsigned hashedFiles = 0;
|
||||
|
||||
updateProgress = 5.0;
|
||||
//Calculate the hashes of all listed files, and queue the download if they need to be updated
|
||||
for(auto f = files.begin(), fend = files.end(); f != fend; ++f) {
|
||||
auto md5 = hash(f->first);
|
||||
++hashedFiles;
|
||||
|
||||
if(md5.zero()) {
|
||||
if(f->second.zero())
|
||||
continue;
|
||||
md5 = anyHash;
|
||||
}
|
||||
updateProgress = 5.0 + 45.0 * std::min(1.0, (double)hashedFiles / 2000.0) + 45.0 * (double)downloaded / (double)totalFiles;
|
||||
if(md5 == f->second)
|
||||
continue;
|
||||
queueDownload(f->first, md5, f->second);
|
||||
}
|
||||
|
||||
while((!queuedDownloads.empty() || !activeDownloads.empty()) && failures < 25) {
|
||||
checkDownloads(true);
|
||||
if(totalFiles > 0)
|
||||
updateProgress = 50.0 + 45.0 * (double)downloaded / (double)totalFiles;
|
||||
threads::sleep(1);
|
||||
}
|
||||
|
||||
while(!activeDownloads.empty()) {
|
||||
checkDownloads(false);
|
||||
if(totalFiles > 0)
|
||||
updateProgress = 50.0 + 45.0 * (double)downloaded / (double)totalFiles;
|
||||
threads::sleep(1);
|
||||
}
|
||||
|
||||
updateProgress = 95.0;
|
||||
|
||||
if(!queuedDownloads.empty()) {
|
||||
updateStatus = -1;
|
||||
isUpdating.signalDown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Delete queued files
|
||||
if(!queuedDeletions.empty()) {
|
||||
std::ofstream deletions(profile + ".delete.txt", std::ios_base::out);
|
||||
for(auto f = queuedDeletions.begin(), fend = queuedDeletions.end(); f != fend; ++f)
|
||||
deletions << *f << std::endl;
|
||||
deletions.flush();
|
||||
deletions.close();
|
||||
}
|
||||
|
||||
//Queue patcher execution and shut down the game
|
||||
launchPatcher = true;
|
||||
|
||||
updateProgress = 100.0;
|
||||
updateStatus = 1;
|
||||
isUpdating.signalDown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateGame() {
|
||||
threads::Lock lock(updateLock);
|
||||
if(isUpdating.check(0)) {
|
||||
isUpdating.signalUp();
|
||||
updateStatus = 0;
|
||||
threads::async(GameUpdate);
|
||||
}
|
||||
}
|
||||
std::string formatURI(const std::string& uri, std::string param) {
|
||||
return replaced(format(uri.c_str(),
|
||||
replaced(param, "&", "&")),
|
||||
" ", "%20");
|
||||
}
|
||||
|
||||
bool intoMember(WebData& dat, rapidjson::Value*& node, const char* name) {
|
||||
if(!node->IsObject()) {
|
||||
dat.errorStr = "Invalid json output. Not an object. "+toString(node->GetType());
|
||||
return false;
|
||||
}
|
||||
rapidjson::Value::Member* mem = node->FindMember(name);
|
||||
if(!mem) {
|
||||
dat.errorStr = "Invalid json output. No member "+std::string(name);
|
||||
return false;
|
||||
}
|
||||
node = &mem->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intoMemberNum(WebData& dat, rapidjson::Value*& node, unsigned ind) {
|
||||
if(!node->IsObject()) {
|
||||
dat.errorStr = "Invalid json output. Not an object.";
|
||||
return false;
|
||||
}
|
||||
auto it = node->MemberBegin();
|
||||
while(ind-- && it != node->MemberEnd())
|
||||
++it;
|
||||
if(it == node->MemberEnd()) {
|
||||
dat.errorStr = "Invalid json output.";
|
||||
return false;
|
||||
}
|
||||
|
||||
node = &it->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intoArray(WebData& dat, rapidjson::Value*& node, unsigned ind) {
|
||||
if(!node->IsArray()) {
|
||||
dat.errorStr = "Invalid json output. Not an array.";
|
||||
return false;
|
||||
}
|
||||
if(ind >= node->Size()) {
|
||||
dat.errorStr = "Invalid json output.";
|
||||
return false;
|
||||
}
|
||||
|
||||
node = &(*node)[ind];
|
||||
return true;
|
||||
}
|
||||
|
||||
void WikiJSON(WebData& dat) {
|
||||
if(dat.wasError())
|
||||
return;
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<0>(dat.result.c_str());
|
||||
|
||||
rapidjson::Value* cursor = &doc;
|
||||
if(!intoMember(dat, cursor, "query"))
|
||||
return;
|
||||
if(!intoMember(dat, cursor, "pages"))
|
||||
return;
|
||||
if(!intoMemberNum(dat, cursor, 0))
|
||||
return;
|
||||
if(!intoMember(dat, cursor, "revisions"))
|
||||
return;
|
||||
if(!intoArray(dat, cursor, 0))
|
||||
return;
|
||||
if(!intoMember(dat, cursor, "*"))
|
||||
return;
|
||||
|
||||
if(!cursor->IsString()) {
|
||||
dat.errorStr = "Invalid json output.";
|
||||
return;
|
||||
}
|
||||
|
||||
dat.result = cursor->GetString();
|
||||
}
|
||||
|
||||
static void getWikiPage(const std::string& title, WebData& dat) {
|
||||
std::string uri = formatURI(WikiURI, title);
|
||||
dat.request(uri, WikiJSON);
|
||||
}
|
||||
|
||||
static void webAPICall(const std::string& page, WebData& dat) {
|
||||
std::string uri = format(APIURI.c_str(), replaced(page, " ", "%20"));
|
||||
|
||||
auto* token = devices.settings.engine.getSetting("sAPIToken");
|
||||
if(token)
|
||||
dat.addHeader("APIToken", token->toString());
|
||||
|
||||
dat.request(uri);
|
||||
}
|
||||
|
||||
void RegisterWebBinds() {
|
||||
ClassBind wd("WebData", asOBJ_REF);
|
||||
classdoc(wd, "Can be used to do requests to data located on the web.");
|
||||
|
||||
wd.addFactory("WebData@ f()", asFUNCTION(makeWebData));
|
||||
wd.setReferenceFuncs(asMETHOD(WebData, grab), asMETHOD(WebData, drop));
|
||||
|
||||
wd.addMethod("bool get_completed()", asMETHOD(WebData, isCompleted))
|
||||
doc("", "Whether the request that was given has completed yet.");
|
||||
wd.addMethod("bool get_error()", asMETHOD(WebData, wasError))
|
||||
doc("", "Whether the request ended in an error.");
|
||||
wd.addMethod("const string& get_result()", asMETHOD(WebData, getResult))
|
||||
doc("", "The result data from the request.");
|
||||
wd.addMethod("const string& get_errorStr()", asMETHOD(WebData, getError))
|
||||
doc("", "The error that was encountered.");
|
||||
wd.addMethod("void addPost(const string& name, const string& data)", asMETHOD(WebData, addPost))
|
||||
doc("Add a post parameter to the request.", "Parameter name.", "Parameter data.");
|
||||
|
||||
bind("void getWikiPage(const string&in title, WebData& dat)", asFUNCTION(getWikiPage))
|
||||
doc("Load the contents of a page from the wiki.", "Wiki page title to load.",
|
||||
"WebData to use for the loading.");
|
||||
|
||||
bind("void webAPICall(const string& page, WebData& dat)", asFUNCTION(webAPICall))
|
||||
doc("Make a call to the web API to get data.", "API page to call.", "WebData to use for the loading.");
|
||||
|
||||
bind("void updateGame()", asFUNCTION(updateGame));
|
||||
bind("bool get_updating()", asFUNCTION(getIsUpdating));
|
||||
bindGlobal("int updateStatus", &updateStatus);
|
||||
bindGlobal("double updateProgress", &updateProgress);
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user