mirror of
https://github.com/zebrajr/SamRewritten.git
synced 2025-12-06 12:19:51 +01:00
Implement first half of json encodings
Implemented all of get_achievements on server side and client side, ack, and quit_game. achievement_t to json transformation needs to be standardized, and will be done next commit.
This commit is contained in:
parent
769c645d96
commit
c6c1aaee9e
121
src/MySteam.cpp
121
src/MySteam.cpp
|
|
@ -3,6 +3,8 @@
|
|||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <dirent.h>
|
||||
#include <yajl/yajl_gen.h>
|
||||
#include <yajl/yajl_tree.h>
|
||||
#include "types/Game.h"
|
||||
#include "types/Actions.h"
|
||||
#include "SteamAppDAO.h"
|
||||
|
|
@ -125,9 +127,8 @@ MySteam::refresh_owned_apps() {
|
|||
closedir(dirp);
|
||||
|
||||
/*
|
||||
// TODO: Scanning through all apps using app_is_owned is far too slow
|
||||
// It takes minutes for SAM to start up if this code is enabled
|
||||
// Implement something to speed this code up before re-enabling it
|
||||
// TODO: Scanning through all apps with this method results in not receiving
|
||||
// any apps
|
||||
Game_t game;
|
||||
SteamAppDAO* appDAO = SteamAppDAO::get_instance();
|
||||
|
||||
|
|
@ -249,23 +250,100 @@ MySteam::refresh_icons() {
|
|||
// => refresh_icons
|
||||
|
||||
|
||||
std::vector<Achievement_t>
|
||||
std::vector<std::pair<std::string, bool>>
|
||||
MySteam::get_achievements() {
|
||||
std::vector<std::pair<std::string, bool>> achs;
|
||||
std::string response;
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
|
||||
if (m_ipc_socket == nullptr) {
|
||||
std::cerr << "Connection to game is broken" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
m_ipc_socket->request_response(GET_ACHIEVEMENTS_STR);
|
||||
|
||||
//TODO: process reponse achievements
|
||||
//This type might not end up being a std::vector<Achievement_t> type,
|
||||
//it may just conform to the JSON types
|
||||
std::vector<Achievement_t> yes;
|
||||
yes.clear();
|
||||
return yes;
|
||||
|
||||
achs.clear();
|
||||
|
||||
// Maybe these MySteam functions should be moved to a MyGameClient.cpp?
|
||||
|
||||
//TODO encapsulate these into a json generator
|
||||
yajl_gen handle = yajl_gen_alloc(NULL);
|
||||
yajl_gen_map_open(handle);
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)SAM_ACTION_STR, strlen(SAM_ACTION_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
return achs;
|
||||
}
|
||||
if (yajl_gen_string(handle, (const unsigned char *)GET_ACHIEVEMENTS_STR, strlen(GET_ACHIEVEMENTS_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
return achs;
|
||||
}
|
||||
if (yajl_gen_map_close(handle) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
return achs;
|
||||
}
|
||||
yajl_gen_get_buf(handle, &buf, &len);
|
||||
response = m_ipc_socket->request_response(std::string((const char*)buf));
|
||||
yajl_gen_free(handle);
|
||||
|
||||
//parse response
|
||||
yajl_val node = yajl_tree_parse(response.c_str(), NULL, 0);
|
||||
|
||||
if (node == NULL) {
|
||||
std::cerr << "parsing error";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char * path1[] = { SAM_ACK_STR, (const char*)0 };
|
||||
yajl_val v = yajl_tree_get(node, path1, yajl_t_string);
|
||||
if (v == NULL || !YAJL_IS_STRING(v)) {
|
||||
std::cerr << "failed to parse " << SAM_ACK_STR << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (std::string(YAJL_GET_STRING(v)) != std::string(SAM_ACK_STR)) {
|
||||
std::cerr << "failed to receive ack" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char * path2[] = { ACHIEVEMENT_LIST_STR, (const char*)0 };
|
||||
|
||||
v = yajl_tree_get(node, path2, yajl_t_array);
|
||||
if (v == NULL) {
|
||||
std::cerr << "parsing error" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
yajl_val *w = YAJL_GET_ARRAY(v)->values;
|
||||
size_t array_len = YAJL_GET_ARRAY(v)->len;
|
||||
|
||||
for(unsigned i = 0; i < array_len; i++) {
|
||||
const char * path3[] = { ACHIEVEMENT_NAME_STR, (const char*)0 };
|
||||
const char * path4[] = { ACHIEVED_STR, (const char*)0 };
|
||||
|
||||
yajl_val cur_node = w[i];
|
||||
|
||||
yajl_val x = yajl_tree_get(cur_node, path3, yajl_t_string);
|
||||
if (x == NULL) {
|
||||
std::cerr << "parsing error" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// why is bool parsing weird
|
||||
yajl_val y = yajl_tree_get(cur_node, path4, yajl_t_any);
|
||||
if (y == NULL) {
|
||||
std::cerr << "parsing error" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!YAJL_IS_TRUE(y) && !YAJL_IS_FALSE(y)) {
|
||||
std::cerr << "bool parsing error" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
achs.push_back(std::pair<std::string, bool>(YAJL_GET_STRING(x), YAJL_IS_TRUE(y)));
|
||||
}
|
||||
|
||||
return achs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -289,4 +367,19 @@ MySteam::remove_modification_ach(const std::string& ach_id) {
|
|||
m_pending_ach_modifications.erase(ach_id);
|
||||
}
|
||||
}
|
||||
// => remove_modification_ach
|
||||
// => remove_modification_ach
|
||||
|
||||
/**
|
||||
* Commit pending achievement changes
|
||||
*/
|
||||
void
|
||||
MySteam::commit_changes(void) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public:
|
|||
*
|
||||
* TODO: maybe don't name this the same as GameServer::get_achievements?
|
||||
*/
|
||||
std::vector<Achievement_t> get_achievements();
|
||||
std::vector<std::pair<std::string, bool>> get_achievements();
|
||||
|
||||
/**
|
||||
* Adds a modification to be done on the launched app.
|
||||
|
|
@ -108,6 +108,11 @@ public:
|
|||
*/
|
||||
//void add_modification_stat(const std::string& stat_id, const double& new_value); // TODO: IMPLEMENT
|
||||
|
||||
/**
|
||||
* Commit pending changes
|
||||
*/
|
||||
void commit_changes(void);
|
||||
|
||||
MySteam(MySteam const&) = delete;
|
||||
void operator=(MySteam const&) = delete;
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -96,16 +96,27 @@ extern "C"
|
|||
if( appId != 0 ) {
|
||||
g_main_gui->switch_to_stats_page();
|
||||
g_steam->launch_game(appId);
|
||||
// get_achievements from launched child
|
||||
std::vector<Achievement_t> ach_list = g_steam->get_achievements();
|
||||
//TODO: populate achievements in GUI (rip out update view from GameEmulator)
|
||||
/*
|
||||
for(unsigned i = 0; i < m_achievement_count; i++) {
|
||||
g_main_gui->add_to_achievement_list(m_achievement_list[i]);
|
||||
// get_achievements from game server
|
||||
std::vector<std::pair<std::string, bool>> ach_list = g_steam->get_achievements();
|
||||
|
||||
g_main_gui->reset_achievements_list();
|
||||
|
||||
//TODO: just pass in the array directly?
|
||||
for(unsigned i = 0; i < ach_list.size(); i++) {
|
||||
|
||||
// For now, for compatibility reasons, just convert to an Achievement_t
|
||||
// These two types will need to be unified
|
||||
Achievement_t ach = { 0 };
|
||||
strncpy(ach.id, ach_list[i].first.c_str(), MAX_ACHIEVEMENT_ID_LENGTH);
|
||||
// incorrect
|
||||
strncpy(ach.name, ach_list[i].first.c_str(), MAX_ACHIEVEMENT_NAME_LENGTH);
|
||||
ach.achieved = ach_list[i].second;
|
||||
|
||||
g_main_gui->add_to_achievement_list(ach);
|
||||
}
|
||||
|
||||
g_main_gui->confirm_stats_list();
|
||||
*/
|
||||
|
||||
} else {
|
||||
std::cerr << "An error occurred figuring out which app to launch.. You can report this to the developer." << std::endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "MyClientSocket.h"
|
||||
#include "../types/Actions.h"
|
||||
#include <yajl/yajl_gen.h>
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
|
@ -48,7 +49,7 @@ MyClientSocket::request_response(std::string request)
|
|||
connect_to_server();
|
||||
send_message(request);
|
||||
std::string ret = receive_message();
|
||||
std::cerr << "client receieved" << ret << std::endl;
|
||||
std::cerr << "client receieved " << ret << std::endl;
|
||||
// need to parse this in the case of GET_ACHIEVEMENTS
|
||||
disconnect();
|
||||
return ret;
|
||||
|
|
@ -63,5 +64,24 @@ MyClientSocket::disconnect()
|
|||
void
|
||||
MyClientSocket::kill_server()
|
||||
{
|
||||
request_response(QUIT_GAME_STR);
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
//TODO encapsulate these into a json generator
|
||||
yajl_gen handle = yajl_gen_alloc(NULL);
|
||||
yajl_gen_map_open(handle);
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)SAM_ACTION_STR, strlen(SAM_ACTION_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
if (yajl_gen_string(handle, (const unsigned char *)QUIT_GAME_STR, strlen(QUIT_GAME_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
if (yajl_gen_map_close(handle) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
yajl_gen_get_buf(handle, &buf, &len);
|
||||
request_response(std::string((const char*)buf));
|
||||
yajl_gen_free(handle);
|
||||
|
||||
//TODO parse ack
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#include <yajl/yajl_gen.h>
|
||||
#include <yajl/yajl_tree.h>
|
||||
#include "MyGameSocket.h"
|
||||
#include "../types/Actions.h"
|
||||
|
||||
|
|
@ -10,21 +12,83 @@ m_CallbackUserStatsReceived( this, &MyGameSocket::OnUserStatsReceived )
|
|||
|
||||
std::string
|
||||
MyGameSocket::process_request(std::string request) {
|
||||
// Logic goes here TODO
|
||||
|
||||
//TODO: yajl parse the JSON-encoded request string (then get request type?) or are strings good enough?
|
||||
//SAM_ACTION request_type = get_request_type(request)
|
||||
//
|
||||
//TODO encapsulate these into a json parser?
|
||||
yajl_val node = yajl_tree_parse(request.c_str(), NULL, 0);
|
||||
|
||||
if (node == NULL) {
|
||||
std::cerr << "Parsing error";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char * path[] = { SAM_ACTION_STR, (const char*)0 };
|
||||
yajl_val v = yajl_tree_get(node, path, yajl_t_string);
|
||||
if (v == NULL || !YAJL_IS_STRING(v)) {
|
||||
std::cerr << "failed to get" << SAM_ACTION_STR << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::string action(YAJL_GET_STRING(v));
|
||||
std::string ret;
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
|
||||
// Generate the ack
|
||||
//TODO encapsulate these into a json generator
|
||||
yajl_gen handle = yajl_gen_alloc(NULL);
|
||||
yajl_gen_map_open(handle);
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)SAM_ACK_STR, strlen(SAM_ACK_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
if (yajl_gen_string(handle, (const unsigned char *)SAM_ACK_STR, strlen(SAM_ACK_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
// switch (request_type) {
|
||||
if (request == GET_ACHIEVEMENTS_STR) {
|
||||
if (action == GET_ACHIEVEMENTS_STR) {
|
||||
//case GET_ACHIEVEMENTS:
|
||||
//this requires an async callback
|
||||
std::vector<Achievement_t> achievements = get_achievements();
|
||||
// Steam api is launched in this context, other possible imlementation: game_utils->get_achievements()
|
||||
//ret = JSON::achievement_vector(achievements);
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)ACHIEVEMENT_LIST_STR, strlen(ACHIEVEMENT_LIST_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
if (yajl_gen_array_open(handle) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
// append the achievements to the ack
|
||||
for (Achievement_t achievement : achievements) {
|
||||
std::cout << "achievement.id " << achievement.id << std::endl;
|
||||
|
||||
yajl_gen_map_open(handle);
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)ACHIEVEMENT_NAME_STR, strlen(ACHIEVEMENT_NAME_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
if (yajl_gen_string(handle, (const unsigned char *)achievement.id, strlen(achievement.id)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
if (yajl_gen_string(handle, (const unsigned char *)ACHIEVED_STR, strlen(ACHIEVED_STR)) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
if (yajl_gen_bool(handle, achievement.achieved) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
yajl_gen_map_close(handle);
|
||||
}
|
||||
|
||||
if (yajl_gen_array_close(handle) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
|
||||
//break;
|
||||
} else if (request == STORE_ACHIEVEMENTS_STR) {
|
||||
} else if (action == STORE_ACHIEVEMENTS_STR) {
|
||||
//case STORE_ACHIEVEMENTS:
|
||||
// TODO: achievement ID string, lock or relock boolean
|
||||
//std::vector<std::pair<string, bool>> operations = JSON::parse_achievement_array(request);
|
||||
|
|
@ -33,15 +97,25 @@ MyGameSocket::process_request(std::string request) {
|
|||
//process_achievements(operations); // or game_utils->process_achievements(..)
|
||||
//ret = SAM_ACK_BUT_IN_JSON;
|
||||
//break;
|
||||
} else if (request == QUIT_GAME_STR) {
|
||||
} else if (action == QUIT_GAME_STR) {
|
||||
//case QUIT_GAME:
|
||||
SteamAPI_Shutdown();
|
||||
|
||||
} else {
|
||||
//default:
|
||||
std::cerr << "Invalid command" << std::endl;
|
||||
ret.clear();
|
||||
}
|
||||
|
||||
if (yajl_gen_map_close(handle) != yajl_gen_status_ok) {
|
||||
std::cerr << "failed to make json" << std::endl;
|
||||
}
|
||||
yajl_gen_get_buf(handle, &buf, &len);
|
||||
ret = std::string((const char*)buf);
|
||||
yajl_gen_free(handle);
|
||||
|
||||
yajl_tree_free(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +132,6 @@ MyGameSocket::get_achievements() {
|
|||
|
||||
while (!m_stats_callback_received) {
|
||||
// for debugging how long steam callbacks take
|
||||
//std::cerr << "waiting for callback" << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
SteamAPI_RunCallbacks();
|
||||
}
|
||||
|
|
@ -84,7 +157,7 @@ MyGameSocket::OnUserStatsReceived(UserStatsReceived_t *callback) {
|
|||
}
|
||||
|
||||
m_achievement_list.clear();
|
||||
m_achievement_list.reserve(num_ach);
|
||||
m_achievement_list.resize(num_ach);
|
||||
|
||||
for (unsigned i = 0; i < num_ach ; i++) {
|
||||
// TODO: strncpy is slow, because it fills the remaining space with NULLs
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
#define STORE_ACHIEVEMENTS_STR "STORE_ACHIEVEMENTS"
|
||||
#define QUIT_GAME_STR "QUIT_GAME"
|
||||
|
||||
#define SAM_ACTION_STR "SAM_ACTION"
|
||||
#define ACHIEVEMENT_LIST_STR "ACHIEVEMENT_LIST"
|
||||
#define ACHIEVEMENT_NAME_STR "ACHIEVEMENT_NAME"
|
||||
#define ACHIEVED_STR "ACHIEVED"
|
||||
#define SAM_ACK_STR "SAM_ACK"
|
||||
|
||||
// TODO: Add SAM_START as an action to this too?
|
||||
// Would require more reorg of code structure
|
||||
enum SAM_ACTION {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user