commit d9f9f6e687b0bdadd74bb9756e32b1872bedd24f Author: blackbeard420 Date: Wed Feb 26 20:29:11 2025 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68247b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +sdk +*.o +steamunlock* +steam_appid.txt +*.cache +*.sconsign.dblite \ No newline at end of file diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..2285210 --- /dev/null +++ b/SConstruct @@ -0,0 +1,16 @@ +import os + +AddOption('--windows', dest='mingw', action='store_true', help='installation prefix') + +env = Environment() + +steamlib = 'steam_api' + +if GetOption('mingw'): + print('detected mingw build') + env.Replace(CXX = 'x86_64-w64-mingw32-g++', LINK = 'x86_64-w64-mingw32-g++', LINKFLAGS = ['-s', '-static'], LIBPATH = 'sdk/redistributable_bin/win64/', RPATH = 'sdk/redistributable_bin/win64/') + steamlib = 'steam_api64' +else: + env.Replace(LINKFLAGS = ['-s'], LIBPATH = 'sdk/redistributable_bin/linux64/', RPATH = 'sdk/redistributable_bin/linux64/') + +env.Program('steamunlock', source = ['main.cpp'], LIBS = [steamlib]) \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d49d304 --- /dev/null +++ b/main.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "sdk/public/steam/steam_api.h" + +class StatsCallback { + public: + STEAM_CALLBACK(StatsCallback, onrecv, UserStatsReceived_t); + STEAM_CALLBACK(StatsCallback, onsend, UserStatsStored_t); + bool achlist; + bool store_complete; + bool unlockall; + char *achid; +}; + +void StatsCallback::onrecv(UserStatsReceived_t *stats) { + if (achlist) { + for (uint32 i = 0; i < SteamUserStats()->GetNumAchievements(); ++i) { + bool unlocked = false; + + const char *id = SteamUserStats()->GetAchievementName(i); + const char *desc = SteamUserStats()->GetAchievementDisplayAttribute(id, "desc"); + + SteamUserStats()->GetAchievement(id, &unlocked); + + if (!unlocked) { + printf("%s: %s\n", id, desc); + } else { + printf("[UNLOCKED] -> %s: %s\n", id, desc); + } + } + } + + if (achid != nullptr) { + if (unlockall) { + for (uint32 i = 0; i < SteamUserStats()->GetNumAchievements(); ++i) { + const char *name = SteamUserStats()->GetAchievementName(i); + printf("Set achievement: %s\n", name); + SteamUserStats()->SetAchievement(name); + } + } else { + SteamUserStats()->SetAchievement(achid); + printf("Set achievement: %s\n", achid); + } + } + + SteamUserStats()->StoreStats(); +} + +void StatsCallback::onsend(UserStatsStored_t *stats) { + store_complete = true; +} + +int write_appid(char *appid) { + FILE *out = fopen("steam_appid.txt", "w"); + fwrite(appid, sizeof(char), strlen(appid), out); + fclose(out); + return 0; +} + +int usage() { + printf("\ +./steamunlock -l [APPID] [ACHIEVEMENT_ID] \n\ +\t-l \t list all achievements for provided APPID\n\ +\t-h \t this help message\n\ +\n\n"); + + return 0; +} + +int main(int argc, char** argv) { + + bool achlist = false; + char *appid = nullptr; + char *achid = nullptr; + + if (argc <= 1) { + usage(); + return 0; + } + + for (int i = 1; i < argc; ++i) { + char *cur = argv[i]; + if (cur[0] == '-') { + for (int x = 1; x < strlen(cur); ++x) { + switch(cur[x]) { + case 'h': + usage(); + return 0; + case 'l': + achlist = true; + break; + } + } + } else { + if (!appid) { + appid = cur; + } else if (!achid) { + achid = cur; + } + } + } + + printf("list all: %b\nappid: %s\nachid: %s\n\n", achlist, appid, achid); + + write_appid(appid); + + SteamAPI_Init(); + + StatsCallback stats; + stats.achlist = achlist; + stats.store_complete = false; + stats.achid = achid; + stats.unlockall = false; + + if (achid != nullptr && strcmp(stats.achid, "all") == 0) { + stats.unlockall = true; + } + + SteamUserStats()->RequestCurrentStats(); + + for (;;) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + SteamAPI_RunCallbacks(); + + if (stats.store_complete) { + break; + } + } + + SteamAPI_Shutdown(); + + return 0; +}