Files
cell-steam/qjs_steam.cpp
2025-11-25 21:07:35 -06:00

3255 lines
108 KiB
C++

// Include C headers first to get types
#include "cell.h"
#include "jsffi.h"
// C++ headers
#include <steam/steam_api.h>
#include <steam/steam_api_flat.h>
#include <string.h>
// Steam ID wrapper class
static JSClassID js_steamid_id;
typedef struct {
uint64_t id;
} steamid_t;
static void js_steamid_finalizer(JSRuntime *rt, JSValue val) {
steamid_t *sid = (steamid_t*)JS_GetOpaque(val, js_steamid_id);
if (sid) js_free_rt(rt, sid);
}
static JSClassDef js_steamid_class = {
.class_name = "SteamID",
.finalizer = js_steamid_finalizer,
};
static steamid_t *js2steamid(JSContext *js, JSValue val) {
if (JS_GetClassID(val) != js_steamid_id) return NULL;
return (steamid_t*)JS_GetOpaque(val, js_steamid_id);
}
static JSValue steamid2js(JSContext *js, uint64_t id) {
steamid_t *sid = (steamid_t*)js_mallocz(js, sizeof(steamid_t));
if (!sid) return JS_ThrowOutOfMemory(js);
sid->id = id;
JSValue obj = JS_NewObjectClass(js, js_steamid_id);
JS_SetOpaque(obj, sid);
return obj;
}
static JSValue js_steamid_toString(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) {
steamid_t *sid = js2steamid(js, self);
if (!sid) return JS_ThrowTypeError(js, "Expected SteamID");
char buf[32];
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)sid->id);
return JS_NewString(js, buf);
}
static JSValue js_steamid_toNumber(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) {
steamid_t *sid = js2steamid(js, self);
if (!sid) return JS_ThrowTypeError(js, "Expected SteamID");
// Return as a safe JS number (may lose precision for very large IDs)
return JS_NewFloat64(js, (double)sid->id);
}
static const JSCFunctionListEntry js_steamid_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_steamid_toString),
JS_CFUNC_DEF("toNumber", 0, js_steamid_toNumber),
};
// Steam interface pointers
static ISteamUserStats *steam_stats = NULL;
static ISteamApps *steam_apps = NULL;
static ISteamRemoteStorage *steam_remote = NULL;
static ISteamUGC *steam_ugc = NULL;
static ISteamUser *steam_user = NULL;
static ISteamFriends *steam_friends = NULL;
static ISteamUtils *steam_utils = NULL;
static ISteamMatchmaking *steam_matchmaking = NULL;
static ISteamNetworking *steam_networking = NULL;
static ISteamScreenshots *steam_screenshots = NULL;
static ISteamHTTP *steam_http = NULL;
static ISteamInput *steam_input = NULL;
static ISteamInventory *steam_inventory = NULL;
static ISteamMusic *steam_music = NULL;
static bool steam_initialized = false;
extern "C" {
// STEAM INITIALIZATION
JSC_CCALL(steam_init,
if (steam_initialized) {
return JS_NewBool(js, true);
}
ESteamAPIInitResult init_result = SteamAPI_InitFlat(nullptr);
switch (init_result) {
case k_ESteamAPIInitResult_OK:
steam_initialized = true;
break;
case k_ESteamAPIInitResult_NoSteamClient:
return JS_ThrowInternalError(js, "Failed to initialize Steam: Steam client is not running or not logged in");
case k_ESteamAPIInitResult_VersionMismatch:
return JS_ThrowInternalError(js, "Failed to initialize Steam: Steam client version is out of date");
case k_ESteamAPIInitResult_FailedGeneric:
default:
return JS_ThrowInternalError(js, "Failed to initialize Steam: Generic failure (check steam_appid.txt file exists and contains valid AppID)");
}
// Get interface pointers - must be called after SteamAPI_InitFlat succeeds
steam_user = SteamAPI_SteamUser();
steam_utils = SteamAPI_SteamUtils();
steam_friends = SteamAPI_SteamFriends();
steam_apps = SteamAPI_SteamApps();
steam_stats = SteamAPI_SteamUserStats();
steam_remote = SteamAPI_SteamRemoteStorage();
steam_ugc = SteamAPI_SteamUGC();
steam_matchmaking = SteamAPI_SteamMatchmaking();
steam_networking = SteamAPI_SteamNetworking();
steam_screenshots = SteamAPI_SteamScreenshots();
steam_http = SteamAPI_SteamHTTP();
steam_input = SteamAPI_SteamInput();
steam_inventory = SteamAPI_SteamInventory();
steam_music = SteamAPI_SteamMusic();
// Verify critical interfaces were obtained
if (!steam_user) {
steam_initialized = false;
SteamAPI_Shutdown();
return JS_ThrowInternalError(js, "Failed to get Steam user interface");
}
if (!steam_utils) {
steam_initialized = false;
SteamAPI_Shutdown();
return JS_ThrowInternalError(js, "Failed to get Steam utils interface");
}
if (!steam_friends) {
steam_initialized = false;
SteamAPI_Shutdown();
return JS_ThrowInternalError(js, "Failed to get Steam friends interface");
}
// Verify user is logged in
if (!SteamAPI_ISteamUser_BLoggedOn(steam_user)) {
steam_initialized = false;
SteamAPI_Shutdown();
return JS_ThrowInternalError(js, "Steam user is not logged in");
}
return JS_NewBool(js, steam_initialized);
)
JSC_CCALL(steam_shutdown,
if (steam_initialized) {
SteamAPI_Shutdown();
steam_initialized = false;
}
return JS_NULL;
)
JSC_CCALL(steam_run_callbacks,
if (steam_initialized) {
SteamAPI_RunCallbacks();
}
return JS_NULL;
)
// USER STATS & ACHIEVEMENTS
JSC_CCALL(stats_request,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
bool success = SteamAPI_ISteamUserStats_RequestUserStats(steam_stats, SteamAPI_ISteamUser_GetSteamID(steam_user));
return JS_NewBool(js, success);
)
JSC_CCALL(stats_store,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
bool success = SteamAPI_ISteamUserStats_StoreStats(steam_stats);
return JS_NewBool(js, success);
)
JSC_CCALL(stats_get_int,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int32 value;
bool success = SteamAPI_ISteamUserStats_GetStatInt32(steam_stats, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewInt32(js, value);
)
JSC_CCALL(stats_get_float,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
float value;
bool success = SteamAPI_ISteamUserStats_GetStatFloat(steam_stats, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewFloat64(js, value);
)
JSC_CCALL(stats_set_int,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int32 value;
JS_ToInt32(js, &value, argv[1]);
bool success = SteamAPI_ISteamUserStats_SetStatInt32(steam_stats, name, value);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(stats_set_float,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
double dvalue;
JS_ToFloat64(js, &dvalue, argv[1]);
float value = (float)dvalue;
bool success = SteamAPI_ISteamUserStats_SetStatFloat(steam_stats, name, value);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(achievement_get,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
bool achieved;
bool success = SteamAPI_ISteamUserStats_GetAchievement(steam_stats, name, &achieved);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewBool(js, achieved);
)
JSC_CCALL(achievement_set,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUserStats_SetAchievement(steam_stats, name);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(achievement_clear,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUserStats_ClearAchievement(steam_stats, name);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(achievement_count,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint32 count = SteamAPI_ISteamUserStats_GetNumAchievements(steam_stats);
return JS_NewUint32(js, count);
)
JSC_CCALL(achievement_name,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint32 index;
JS_ToUint32(js, &index, argv[0]);
const char *name = SteamAPI_ISteamUserStats_GetAchievementName(steam_stats, index);
if (!name) return JS_NULL;
return JS_NewString(js, name);
)
JSC_CCALL(achievement_get_and_unlock_time,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
bool achieved;
uint32 unlock_time;
bool success = SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime(steam_stats, name, &achieved, &unlock_time);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "achieved", JS_NewBool(js, achieved));
JS_SetPropertyStr(js, obj, "unlock_time", JS_NewUint32(js, unlock_time));
return obj;
)
JSC_CCALL(achievement_get_icon,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int icon = SteamAPI_ISteamUserStats_GetAchievementIcon(steam_stats, name);
JS_FreeCString(js, name);
return JS_NewInt32(js, icon);
)
JSC_CCALL(achievement_get_display_attribute,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
const char *key = JS_ToCString(js, argv[1]);
if (!key) {
JS_FreeCString(js, name);
return JS_EXCEPTION;
}
const char *value = SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute(steam_stats, name, key);
JS_FreeCString(js, name);
JS_FreeCString(js, key);
return JS_NewString(js, value ? value : "");
)
JSC_CCALL(achievement_indicate_progress,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
uint32 cur_progress, max_progress;
JS_ToUint32(js, &cur_progress, argv[1]);
JS_ToUint32(js, &max_progress, argv[2]);
bool success = SteamAPI_ISteamUserStats_IndicateAchievementProgress(steam_stats, name, cur_progress, max_progress);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(achievement_get_user_achievement,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
const char *name = JS_ToCString(js, argv[1]);
if (!name) return JS_EXCEPTION;
bool achieved;
bool success = SteamAPI_ISteamUserStats_GetUserAchievement(steam_stats, sid->id, name, &achieved);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewBool(js, achieved);
)
JSC_CCALL(achievement_get_user_achievement_and_unlock_time,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
const char *name = JS_ToCString(js, argv[1]);
if (!name) return JS_EXCEPTION;
bool achieved;
uint32 unlock_time;
bool success = SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime(steam_stats, sid->id, name, &achieved, &unlock_time);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "achieved", JS_NewBool(js, achieved));
JS_SetPropertyStr(js, obj, "unlock_time", JS_NewUint32(js, unlock_time));
return obj;
)
JSC_CCALL(achievement_get_achieved_percent,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
float percent;
bool success = SteamAPI_ISteamUserStats_GetAchievementAchievedPercent(steam_stats, name, &percent);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewFloat64(js, percent);
)
JSC_CCALL(achievement_get_progress_limits_int,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int32 min_progress, max_progress;
bool success = SteamAPI_ISteamUserStats_GetAchievementProgressLimitsInt32(steam_stats, name, &min_progress, &max_progress);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "min_progress", JS_NewInt32(js, min_progress));
JS_SetPropertyStr(js, obj, "max_progress", JS_NewInt32(js, max_progress));
return obj;
)
JSC_CCALL(achievement_get_progress_limits_float,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
float min_progress, max_progress;
bool success = SteamAPI_ISteamUserStats_GetAchievementProgressLimitsFloat(steam_stats, name, &min_progress, &max_progress);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "min_progress", JS_NewFloat64(js, min_progress));
JS_SetPropertyStr(js, obj, "max_progress", JS_NewFloat64(js, max_progress));
return obj;
)
JSC_CCALL(stats_update_avg_rate,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
double count_this_session, session_length;
JS_ToFloat64(js, &count_this_session, argv[1]);
JS_ToFloat64(js, &session_length, argv[2]);
bool success = SteamAPI_ISteamUserStats_UpdateAvgRateStat(steam_stats, name, (float)count_this_session, session_length);
JS_FreeCString(js, name);
return JS_NewBool(js, success);
)
JSC_CCALL(stats_get_user_stat_int,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
const char *name = JS_ToCString(js, argv[1]);
if (!name) return JS_EXCEPTION;
int32 value;
bool success = SteamAPI_ISteamUserStats_GetUserStatInt32(steam_stats, sid->id, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewInt32(js, value);
)
JSC_CCALL(stats_get_user_stat_float,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
const char *name = JS_ToCString(js, argv[1]);
if (!name) return JS_EXCEPTION;
float value;
bool success = SteamAPI_ISteamUserStats_GetUserStatFloat(steam_stats, sid->id, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewFloat64(js, value);
)
JSC_CCALL(stats_reset_all,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
bool achievements_too = JS_ToBool(js, argv[0]);
bool success = SteamAPI_ISteamUserStats_ResetAllStats(steam_stats, achievements_too);
return JS_NewBool(js, success);
)
JSC_CCALL(leaderboard_find_or_create,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int32 sort_method, display_type;
JS_ToInt32(js, &sort_method, argv[1]);
JS_ToInt32(js, &display_type, argv[2]);
SteamAPICall_t call = SteamAPI_ISteamUserStats_FindOrCreateLeaderboard(steam_stats, name, (ELeaderboardSortMethod)sort_method, (ELeaderboardDisplayType)display_type);
JS_FreeCString(js, name);
return steamid2js(js, call);
)
JSC_CCALL(leaderboard_find,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
SteamAPICall_t call = SteamAPI_ISteamUserStats_FindLeaderboard(steam_stats, name);
JS_FreeCString(js, name);
return steamid2js(js, call);
)
JSC_CCALL(leaderboard_get_name,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
const char *name = SteamAPI_ISteamUserStats_GetLeaderboardName(steam_stats, (SteamLeaderboard_t)leaderboard);
return JS_NewString(js, name ? name : "");
)
JSC_CCALL(leaderboard_get_entry_count,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
int count = SteamAPI_ISteamUserStats_GetLeaderboardEntryCount(steam_stats, (SteamLeaderboard_t)leaderboard);
return JS_NewInt32(js, count);
)
JSC_CCALL(leaderboard_get_sort_method,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
ELeaderboardSortMethod method = SteamAPI_ISteamUserStats_GetLeaderboardSortMethod(steam_stats, (SteamLeaderboard_t)leaderboard);
return JS_NewInt32(js, method);
)
JSC_CCALL(leaderboard_get_display_type,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
ELeaderboardDisplayType type = SteamAPI_ISteamUserStats_GetLeaderboardDisplayType(steam_stats, (SteamLeaderboard_t)leaderboard);
return JS_NewInt32(js, type);
)
JSC_CCALL(leaderboard_download_entries,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
int32 request_type, range_start, range_end;
JS_ToInt32(js, &request_type, argv[1]);
JS_ToInt32(js, &range_start, argv[2]);
JS_ToInt32(js, &range_end, argv[3]);
SteamAPICall_t call = SteamAPI_ISteamUserStats_DownloadLeaderboardEntries(steam_stats, (SteamLeaderboard_t)leaderboard, (ELeaderboardDataRequest)request_type, range_start, range_end);
return steamid2js(js, call);
)
JSC_CCALL(leaderboard_download_entries_for_users,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
// For simplicity, assume single user for now - proper implementation would handle array
steamid_t *sid = js2steamid(js, argv[1]);
if (!sid) return JS_ThrowTypeError(js, "Second argument must be a SteamID");
CSteamID user_id = CSteamID(sid->id);
SteamAPICall_t call = SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers(steam_stats, (SteamLeaderboard_t)leaderboard, &user_id, 1);
return steamid2js(js, call);
)
JSC_CCALL(leaderboard_get_downloaded_entry,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 entries;
JS_ToIndex(js, &entries, argv[0]);
int32 index;
JS_ToInt32(js, &index, argv[1]);
LeaderboardEntry_t entry;
int32 details[32]; // Max details buffer
bool success = SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry(steam_stats, (SteamLeaderboardEntries_t)entries, index, &entry, details, 32);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "steam_id", steamid2js(js, entry.m_steamIDUser.ConvertToUint64()));
JS_SetPropertyStr(js, obj, "global_rank", JS_NewInt32(js, entry.m_nGlobalRank));
JS_SetPropertyStr(js, obj, "score", JS_NewInt32(js, entry.m_nScore));
JS_SetPropertyStr(js, obj, "details_count", JS_NewInt32(js, entry.m_cDetails));
return obj;
)
JSC_CCALL(leaderboard_upload_score,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard;
JS_ToIndex(js, &leaderboard, argv[0]);
int32 upload_method, score;
JS_ToInt32(js, &upload_method, argv[1]);
JS_ToInt32(js, &score, argv[2]);
SteamAPICall_t call = SteamAPI_ISteamUserStats_UploadLeaderboardScore(steam_stats, (SteamLeaderboard_t)leaderboard, (ELeaderboardUploadScoreMethod)upload_method, score, NULL, 0);
return steamid2js(js, call);
)
JSC_CCALL(leaderboard_attach_ugc,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
uint64 leaderboard, ugc_handle;
JS_ToIndex(js, &leaderboard, argv[0]);
JS_ToIndex(js, &ugc_handle, argv[1]);
SteamAPICall_t call = SteamAPI_ISteamUserStats_AttachLeaderboardUGC(steam_stats, (SteamLeaderboard_t)leaderboard, (UGCHandle_t)ugc_handle);
return steamid2js(js, call);
)
JSC_CCALL(stats_get_number_of_current_players,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
SteamAPICall_t call = SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(steam_stats);
return steamid2js(js, call);
)
JSC_CCALL(stats_request_global_achievement_percentages,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
SteamAPICall_t call = SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages(steam_stats);
return steamid2js(js, call);
)
JSC_CCALL(achievement_get_most_achieved_info,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
char name[256];
float percent;
bool achieved;
int result = SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo(steam_stats, name, 256, &percent, &achieved);
if (result <= 0) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "name", JS_NewString(js, name));
JS_SetPropertyStr(js, obj, "percent", JS_NewFloat64(js, percent));
JS_SetPropertyStr(js, obj, "achieved", JS_NewBool(js, achieved));
return obj;
)
JSC_CCALL(achievement_get_next_most_achieved_info,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
int32 iterator_previous;
JS_ToInt32(js, &iterator_previous, argv[0]);
char name[256];
float percent;
bool achieved;
int result = SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo(steam_stats, iterator_previous, name, 256, &percent, &achieved);
if (result <= 0) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "name", JS_NewString(js, name));
JS_SetPropertyStr(js, obj, "percent", JS_NewFloat64(js, percent));
JS_SetPropertyStr(js, obj, "achieved", JS_NewBool(js, achieved));
JS_SetPropertyStr(js, obj, "iterator", JS_NewInt32(js, result));
return obj;
)
JSC_CCALL(stats_request_global,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
int32 history_days;
JS_ToInt32(js, &history_days, argv[0]);
SteamAPICall_t call = SteamAPI_ISteamUserStats_RequestGlobalStats(steam_stats, history_days);
return steamid2js(js, call);
)
JSC_CCALL(stats_get_global_stat_int64,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int64 value;
bool success = SteamAPI_ISteamUserStats_GetGlobalStatInt64(steam_stats, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return steamid2js(js, value);
)
JSC_CCALL(stats_get_global_stat_double,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
double value;
bool success = SteamAPI_ISteamUserStats_GetGlobalStatDouble(steam_stats, name, &value);
JS_FreeCString(js, name);
if (!success) return JS_NULL;
return JS_NewFloat64(js, value);
)
JSC_CCALL(stats_get_global_stat_history_int64,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
int64 data[100]; // Buffer for history data
int32 result = SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64(steam_stats, name, data, sizeof(data));
JS_FreeCString(js, name);
if (result <= 0) return JS_NULL;
JSValue arr = JS_NewArray(js);
for (int i = 0; i < result; i++) {
JS_SetPropertyUint32(js, arr, i, steamid2js(js, data[i]));
}
return arr;
)
JSC_CCALL(stats_get_global_stat_history_double,
if (!steam_stats) return JS_ThrowInternalError(js, "Steam stats not initialized");
const char *name = JS_ToCString(js, argv[0]);
if (!name) return JS_EXCEPTION;
double data[100]; // Buffer for history data
int32 result = SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble(steam_stats, name, data, sizeof(data));
JS_FreeCString(js, name);
if (result <= 0) return JS_NULL;
JSValue arr = JS_NewArray(js);
for (int i = 0; i < result; i++) {
JS_SetPropertyUint32(js, arr, i, JS_NewFloat64(js, data[i]));
}
return arr;
)
// APPS
JSC_CCALL(app_id,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
AppId_t appid = SteamAPI_ISteamUtils_GetAppID(steam_utils);
return JS_NewUint32(js, appid);
)
JSC_CCALL(app_owner,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
uint64_steamid owner = SteamAPI_ISteamApps_GetAppOwner(steam_apps);
return steamid2js(js, owner);
)
JSC_CCALL(app_installed,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
uint32 appid;
JS_ToUint32(js, &appid, argv[0]);
bool installed = SteamAPI_ISteamApps_BIsAppInstalled(steam_apps, appid);
return JS_NewBool(js, installed);
)
JSC_CCALL(app_subscribed,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool subscribed = SteamAPI_ISteamApps_BIsSubscribed(steam_apps);
return JS_NewBool(js, subscribed);
)
JSC_CCALL(app_language,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
const char *lang = SteamAPI_ISteamApps_GetCurrentGameLanguage(steam_apps);
return JS_NewString(js, lang ? lang : "english");
)
JSC_CCALL(app_dlc_installed,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t dlcid;
JS_ToUint32(js, &dlcid, argv[0]);
bool installed = SteamAPI_ISteamApps_BIsDlcInstalled(steam_apps, dlcid);
return JS_NewBool(js, installed);
)
JSC_CCALL(app_is_low_violence,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool low_violence = SteamAPI_ISteamApps_BIsLowViolence(steam_apps);
return JS_NewBool(js, low_violence);
)
JSC_CCALL(app_is_cybercafe,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool cybercafe = SteamAPI_ISteamApps_BIsCybercafe(steam_apps);
return JS_NewBool(js, cybercafe);
)
JSC_CCALL(app_is_vac_banned,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool vac_banned = SteamAPI_ISteamApps_BIsVACBanned(steam_apps);
return JS_NewBool(js, vac_banned);
)
JSC_CCALL(app_available_languages,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
const char *languages = SteamAPI_ISteamApps_GetAvailableGameLanguages(steam_apps);
return JS_NewString(js, languages ? languages : "");
)
JSC_CCALL(app_is_subscribed_app,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
bool subscribed = SteamAPI_ISteamApps_BIsSubscribedApp(steam_apps, appid);
return JS_NewBool(js, subscribed);
)
JSC_CCALL(app_earliest_purchase_time,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
uint32 time = SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime(steam_apps, appid);
return JS_NewUint32(js, time);
)
JSC_CCALL(app_is_subscribed_from_free_weekend,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool free_weekend = SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend(steam_apps);
return JS_NewBool(js, free_weekend);
)
JSC_CCALL(app_dlc_count,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
int count = SteamAPI_ISteamApps_GetDLCCount(steam_apps);
return JS_NewInt32(js, count);
)
JSC_CCALL(app_get_dlc_data_by_index,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
int index;
JS_ToInt32(js, &index, argv[0]);
AppId_t appid;
bool available;
char name[256];
bool success = SteamAPI_ISteamApps_BGetDLCDataByIndex(steam_apps, index, &appid, &available, name, sizeof(name));
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "appid", JS_NewUint32(js, appid));
JS_SetPropertyStr(js, obj, "available", JS_NewBool(js, available));
JS_SetPropertyStr(js, obj, "name", JS_NewString(js, name));
return obj;
)
JSC_CCALL(app_install_dlc,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
SteamAPI_ISteamApps_InstallDLC(steam_apps, appid);
return JS_NULL;
)
JSC_CCALL(app_uninstall_dlc,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
SteamAPI_ISteamApps_UninstallDLC(steam_apps, appid);
return JS_NULL;
)
JSC_CCALL(app_request_proof_of_purchase_key,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey(steam_apps, appid);
return JS_NULL;
)
JSC_CCALL(app_get_current_beta_name,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
char beta_name[256];
bool has_beta = SteamAPI_ISteamApps_GetCurrentBetaName(steam_apps, beta_name, sizeof(beta_name));
if (!has_beta) return JS_NULL;
return JS_NewString(js, beta_name);
)
JSC_CCALL(app_mark_content_corrupt,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool missing_files_only = false;
if (argc > 0) {
missing_files_only = JS_ToBool(js, argv[0]);
}
bool success = SteamAPI_ISteamApps_MarkContentCorrupt(steam_apps, missing_files_only);
return JS_NewBool(js, success);
)
JSC_CCALL(app_get_installed_depots,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
const uint32 max_depots = 32;
DepotId_t depots[max_depots];
uint32 count = SteamAPI_ISteamApps_GetInstalledDepots(steam_apps, appid, depots, max_depots);
JSValue arr = JS_NewArray(js);
for (uint32 i = 0; i < count; i++) {
JS_SetPropertyUint32(js, arr, i, JS_NewUint32(js, depots[i]));
}
return arr;
)
JSC_CCALL(app_get_install_dir,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
char folder[512];
uint32 size = SteamAPI_ISteamApps_GetAppInstallDir(steam_apps, appid, folder, sizeof(folder));
if (size == 0) return JS_NULL;
return JS_NewString(js, folder);
)
JSC_CCALL(app_get_launch_query_param,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
const char *key = JS_ToCString(js, argv[0]);
if (!key) return JS_ThrowTypeError(js, "Expected string parameter");
const char *value = SteamAPI_ISteamApps_GetLaunchQueryParam(steam_apps, key);
JS_FreeCString(js, key);
if (!value) return JS_NULL;
return JS_NewString(js, value);
)
JSC_CCALL(app_get_dlc_download_progress,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
uint64 bytes_downloaded, bytes_total;
bool success = SteamAPI_ISteamApps_GetDlcDownloadProgress(steam_apps, appid, &bytes_downloaded, &bytes_total);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "downloaded", steamid2js(js, bytes_downloaded));
JS_SetPropertyStr(js, obj, "total", steamid2js(js, bytes_total));
return obj;
)
JSC_CCALL(app_get_build_id,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
int build_id = SteamAPI_ISteamApps_GetAppBuildId(steam_apps);
return JS_NewInt32(js, build_id);
)
JSC_CCALL(app_request_all_proof_of_purchase_keys,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys(steam_apps);
return JS_NULL;
)
JSC_CCALL(app_get_file_details,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_ThrowTypeError(js, "Expected string parameter");
SteamAPICall_t call = SteamAPI_ISteamApps_GetFileDetails(steam_apps, filename);
JS_FreeCString(js, filename);
return steamid2js(js, call);
)
JSC_CCALL(app_get_launch_command_line,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
char command_line[1024];
int size = SteamAPI_ISteamApps_GetLaunchCommandLine(steam_apps, command_line, sizeof(command_line));
if (size <= 0) return JS_NULL;
return JS_NewString(js, command_line);
)
JSC_CCALL(app_is_subscribed_from_family_sharing,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
bool family_sharing = SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing(steam_apps);
return JS_NewBool(js, family_sharing);
)
JSC_CCALL(app_is_timed_trial,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
uint32 seconds_allowed, seconds_played;
bool is_trial = SteamAPI_ISteamApps_BIsTimedTrial(steam_apps, &seconds_allowed, &seconds_played);
if (!is_trial) return JS_NewBool(js, false);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "is_trial", JS_NewBool(js, true));
JS_SetPropertyStr(js, obj, "seconds_allowed", JS_NewUint32(js, seconds_allowed));
JS_SetPropertyStr(js, obj, "seconds_played", JS_NewUint32(js, seconds_played));
return obj;
)
JSC_CCALL(app_set_dlc_context,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
AppId_t appid;
JS_ToUint32(js, &appid, argv[0]);
bool success = SteamAPI_ISteamApps_SetDlcContext(steam_apps, appid);
return JS_NewBool(js, success);
)
JSC_CCALL(app_get_num_betas,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
int available, private_betas;
int total = SteamAPI_ISteamApps_GetNumBetas(steam_apps, &available, &private_betas);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "total", JS_NewInt32(js, total));
JS_SetPropertyStr(js, obj, "available", JS_NewInt32(js, available));
JS_SetPropertyStr(js, obj, "private", JS_NewInt32(js, private_betas));
return obj;
)
JSC_CCALL(app_get_beta_info,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
int beta_index;
JS_ToInt32(js, &beta_index, argv[0]);
uint32 flags, build_id;
char beta_name[128], description[512];
bool success = SteamAPI_ISteamApps_GetBetaInfo(steam_apps, beta_index, &flags, &build_id,
beta_name, sizeof(beta_name),
description, sizeof(description));
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "flags", JS_NewUint32(js, flags));
JS_SetPropertyStr(js, obj, "build_id", JS_NewUint32(js, build_id));
JS_SetPropertyStr(js, obj, "name", JS_NewString(js, beta_name));
JS_SetPropertyStr(js, obj, "description", JS_NewString(js, description));
return obj;
)
JSC_CCALL(app_set_active_beta,
if (!steam_apps) return JS_ThrowInternalError(js, "Steam apps not initialized");
const char *beta_name = JS_ToCString(js, argv[0]);
if (!beta_name) return JS_ThrowTypeError(js, "Expected string parameter");
bool success = SteamAPI_ISteamApps_SetActiveBeta(steam_apps, beta_name);
JS_FreeCString(js, beta_name);
return JS_NewBool(js, success);
)
// USER
JSC_CCALL(user_logged_on,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool logged = SteamAPI_ISteamUser_BLoggedOn(steam_user);
return JS_NewBool(js, logged);
)
JSC_CCALL(user_steam_id,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint64_steamid id = SteamAPI_ISteamUser_GetSteamID(steam_user);
return steamid2js(js, id);
)
JSC_CCALL(user_level,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
int level = SteamAPI_ISteamUser_GetPlayerSteamLevel(steam_user);
return JS_NewInt32(js, level);
)
JSC_CCALL(user_hsteam_user,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
HSteamUser user = SteamAPI_ISteamUser_GetHSteamUser(steam_user);
return JS_NewUint32(js, user);
)
JSC_CCALL(user_get_user_data_folder,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
char buffer[1024];
bool success = SteamAPI_ISteamUser_GetUserDataFolder(steam_user, buffer, sizeof(buffer));
if (!success) return JS_NULL;
return JS_NewString(js, buffer);
)
JSC_CCALL(user_start_voice_recording,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
SteamAPI_ISteamUser_StartVoiceRecording(steam_user);
return JS_NULL;
)
JSC_CCALL(user_stop_voice_recording,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
SteamAPI_ISteamUser_StopVoiceRecording(steam_user);
return JS_NULL;
)
JSC_CCALL(user_get_available_voice,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint32 compressed, uncompressed_deprecated;
uint32 sample_rate = 11025;
if (argc > 0) JS_ToUint32(js, &sample_rate, argv[0]);
EVoiceResult result = SteamAPI_ISteamUser_GetAvailableVoice(steam_user, &compressed, &uncompressed_deprecated, sample_rate);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "result", JS_NewInt32(js, result));
JS_SetPropertyStr(js, obj, "compressed_bytes", JS_NewUint32(js, compressed));
return obj;
)
JSC_CCALL(user_get_voice,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint32 buffer_size = 8192;
if (argc > 0) JS_ToUint32(js, &buffer_size, argv[0]);
void *buffer = js_malloc(js, buffer_size);
if (!buffer) return JS_ThrowOutOfMemory(js);
uint32 bytes_written;
EVoiceResult result = SteamAPI_ISteamUser_GetVoice(steam_user, true, buffer, buffer_size, &bytes_written, false, NULL, 0, NULL, 0);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "result", JS_NewInt32(js, result));
if (result == k_EVoiceResultOK && bytes_written > 0) {
JSValue blob = js_new_blob_stoned_copy(js, buffer, bytes_written);
JS_SetPropertyStr(js, obj, "data", blob);
JS_SetPropertyStr(js, obj, "bytes_written", JS_NewUint32(js, bytes_written));
}
js_free(js, buffer);
return obj;
)
JSC_CCALL(user_decompress_voice,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
size_t compressed_size;
void *compressed_data = js_get_blob_data(js, &compressed_size, argv[0]);
if (!compressed_data) return JS_ThrowTypeError(js, "First argument must be a blob");
uint32 dest_buffer_size = 22050 * 2;
uint32 sample_rate = 22050;
if (argc > 1) JS_ToUint32(js, &dest_buffer_size, argv[1]);
if (argc > 2) JS_ToUint32(js, &sample_rate, argv[2]);
void *dest_buffer = js_malloc(js, dest_buffer_size);
if (!dest_buffer) return JS_ThrowOutOfMemory(js);
uint32 bytes_written;
EVoiceResult result = SteamAPI_ISteamUser_DecompressVoice(steam_user, compressed_data, compressed_size, dest_buffer, dest_buffer_size, &bytes_written, sample_rate);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "result", JS_NewInt32(js, result));
if (result == k_EVoiceResultOK && bytes_written > 0) {
JSValue blob = js_new_blob_stoned_copy(js, dest_buffer, bytes_written);
JS_SetPropertyStr(js, obj, "data", blob);
JS_SetPropertyStr(js, obj, "bytes_written", JS_NewUint32(js, bytes_written));
}
js_free(js, dest_buffer);
return obj;
)
JSC_CCALL(user_get_voice_optimal_sample_rate,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint32 rate = SteamAPI_ISteamUser_GetVoiceOptimalSampleRate(steam_user);
return JS_NewUint32(js, rate);
)
JSC_CCALL(user_get_auth_session_ticket,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint8_t ticket[1024];
uint32 ticket_size;
HAuthTicket auth_ticket = SteamAPI_ISteamUser_GetAuthSessionTicket(steam_user, ticket, sizeof(ticket), &ticket_size, NULL);
if (auth_ticket == k_HAuthTicketInvalid) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "auth_ticket", JS_NewUint32(js, auth_ticket));
if (ticket_size > 0) {
JSValue blob = js_new_blob_stoned_copy(js, ticket, ticket_size);
JS_SetPropertyStr(js, obj, "ticket_data", blob);
JS_SetPropertyStr(js, obj, "ticket_size", JS_NewUint32(js, ticket_size));
}
return obj;
)
JSC_CCALL(user_get_auth_ticket_for_web_api,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
const char *identity = JS_ToCString(js, argv[0]);
if (!identity) return JS_EXCEPTION;
HAuthTicket auth_ticket = SteamAPI_ISteamUser_GetAuthTicketForWebApi(steam_user, identity);
JS_FreeCString(js, identity);
if (auth_ticket == k_HAuthTicketInvalid) return JS_NULL;
return JS_NewUint32(js, auth_ticket);
)
JSC_CCALL(user_begin_auth_session,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
size_t ticket_size;
void *ticket_data = js_get_blob_data(js, &ticket_size, argv[0]);
if (!ticket_data) return JS_ThrowTypeError(js, "First argument must be a blob");
steamid_t *sid = js2steamid(js, argv[1]);
if (!sid) return JS_ThrowTypeError(js, "Second argument must be a SteamID");
EBeginAuthSessionResult result = SteamAPI_ISteamUser_BeginAuthSession(steam_user, ticket_data, ticket_size, sid->id);
return JS_NewInt32(js, result);
)
JSC_CCALL(user_end_auth_session,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
SteamAPI_ISteamUser_EndAuthSession(steam_user, sid->id);
return JS_NULL;
)
JSC_CCALL(user_cancel_auth_ticket,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint32 auth_ticket;
JS_ToUint32(js, &auth_ticket, argv[0]);
SteamAPI_ISteamUser_CancelAuthTicket(steam_user, auth_ticket);
return JS_NULL;
)
JSC_CCALL(user_has_license_for_app,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
uint32 app_id;
JS_ToUint32(js, &app_id, argv[1]);
EUserHasLicenseForAppResult result = SteamAPI_ISteamUser_UserHasLicenseForApp(steam_user, sid->id, app_id);
return JS_NewInt32(js, result);
)
JSC_CCALL(user_is_behind_nat,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool behind_nat = SteamAPI_ISteamUser_BIsBehindNAT(steam_user);
return JS_NewBool(js, behind_nat);
)
JSC_CCALL(user_advertise_game,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
uint32 ip_server, port_server;
JS_ToUint32(js, &ip_server, argv[1]);
JS_ToUint32(js, &port_server, argv[2]);
SteamAPI_ISteamUser_AdvertiseGame(steam_user, sid->id, ip_server, (uint16)port_server);
return JS_NULL;
)
JSC_CCALL(user_request_encrypted_app_ticket,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
size_t data_size = 0;
void *data = NULL;
if (argc > 0 && !JS_IsNull(argv[0])) {
data = js_get_blob_data(js, &data_size, argv[0]);
if (!data) return JS_ThrowTypeError(js, "First argument must be a blob or null");
}
SteamAPICall_t call = SteamAPI_ISteamUser_RequestEncryptedAppTicket(steam_user, data, data_size);
return steamid2js(js, call);
)
JSC_CCALL(user_get_encrypted_app_ticket,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint8_t ticket[1024];
uint32 ticket_size;
bool success = SteamAPI_ISteamUser_GetEncryptedAppTicket(steam_user, ticket, sizeof(ticket), &ticket_size);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
if (ticket_size > 0) {
JSValue blob = js_new_blob_stoned_copy(js, ticket, ticket_size);
JS_SetPropertyStr(js, obj, "ticket_data", blob);
JS_SetPropertyStr(js, obj, "ticket_size", JS_NewUint32(js, ticket_size));
}
return obj;
)
JSC_CCALL(user_get_game_badge_level,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
int32 series;
JS_ToInt32(js, &series, argv[0]);
bool foil = argc > 1 ? JS_ToBool(js, argv[1]) : false;
int level = SteamAPI_ISteamUser_GetGameBadgeLevel(steam_user, series, foil);
return JS_NewInt32(js, level);
)
JSC_CCALL(user_request_store_auth_url,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
const char *redirect_url = JS_ToCString(js, argv[0]);
if (!redirect_url) return JS_EXCEPTION;
SteamAPICall_t call = SteamAPI_ISteamUser_RequestStoreAuthURL(steam_user, redirect_url);
JS_FreeCString(js, redirect_url);
return steamid2js(js, call);
)
JSC_CCALL(user_is_phone_verified,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool verified = SteamAPI_ISteamUser_BIsPhoneVerified(steam_user);
return JS_NewBool(js, verified);
)
JSC_CCALL(user_is_two_factor_enabled,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool enabled = SteamAPI_ISteamUser_BIsTwoFactorEnabled(steam_user);
return JS_NewBool(js, enabled);
)
JSC_CCALL(user_is_phone_identifying,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool identifying = SteamAPI_ISteamUser_BIsPhoneIdentifying(steam_user);
return JS_NewBool(js, identifying);
)
JSC_CCALL(user_is_phone_requiring_verification,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
bool requiring = SteamAPI_ISteamUser_BIsPhoneRequiringVerification(steam_user);
return JS_NewBool(js, requiring);
)
JSC_CCALL(user_get_market_eligibility,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
SteamAPICall_t call = SteamAPI_ISteamUser_GetMarketEligibility(steam_user);
return steamid2js(js, call);
)
JSC_CCALL(user_get_duration_control,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
SteamAPICall_t call = SteamAPI_ISteamUser_GetDurationControl(steam_user);
return steamid2js(js, call);
)
JSC_CCALL(user_set_duration_control_online_state,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
int32 state;
JS_ToInt32(js, &state, argv[0]);
bool success = SteamAPI_ISteamUser_BSetDurationControlOnlineState(steam_user, (EDurationControlOnlineState)state);
return JS_NewBool(js, success);
)
JSC_CCALL(user_track_app_usage_event,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint64 game_id;
JS_ToIndex(js, &game_id, argv[0]);
int32 app_usage_event;
JS_ToInt32(js, &app_usage_event, argv[1]);
const char *extra_info = argc > 2 ? JS_ToCString(js, argv[2]) : "";
SteamAPI_ISteamUser_TrackAppUsageEvent(steam_user, game_id, app_usage_event, extra_info);
if (argc > 2) JS_FreeCString(js, extra_info);
return JS_NULL;
)
JSC_CCALL(user_initiate_game_connection_deprecated,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
steamid_t *server_sid = js2steamid(js, argv[0]);
if (!server_sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
uint32 ip_server, port_server;
JS_ToUint32(js, &ip_server, argv[1]);
JS_ToUint32(js, &port_server, argv[2]);
bool secure = argc > 3 ? JS_ToBool(js, argv[3]) : false;
uint8_t auth_blob[1024];
int result = SteamAPI_ISteamUser_InitiateGameConnection_DEPRECATED(steam_user, auth_blob, sizeof(auth_blob), server_sid->id, ip_server, (uint16)port_server, secure);
if (result <= 0) return JS_NULL;
JSValue obj = JS_NewObject(js);
JSValue blob = js_new_blob_stoned_copy(js, auth_blob, result);
JS_SetPropertyStr(js, obj, "auth_blob", blob);
JS_SetPropertyStr(js, obj, "size", JS_NewInt32(js, result));
return obj;
)
JSC_CCALL(user_terminate_game_connection_deprecated,
if (!steam_user) return JS_ThrowInternalError(js, "Steam user not initialized");
uint32 ip_server, port_server;
JS_ToUint32(js, &ip_server, argv[0]);
JS_ToUint32(js, &port_server, argv[1]);
SteamAPI_ISteamUser_TerminateGameConnection_DEPRECATED(steam_user, ip_server, (uint16)port_server);
return JS_NULL;
)
// FRIENDS
JSC_CCALL(friends_name,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
const char *name = SteamAPI_ISteamFriends_GetPersonaName(steam_friends);
return JS_NewString(js, name ? name : "");
)
JSC_CCALL(friends_state,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
EPersonaState state = SteamAPI_ISteamFriends_GetPersonaState(steam_friends);
const char *state_str;
switch(state) {
case k_EPersonaStateOffline: state_str = "offline"; break;
case k_EPersonaStateOnline: state_str = "online"; break;
case k_EPersonaStateBusy: state_str = "busy"; break;
case k_EPersonaStateAway: state_str = "away"; break;
case k_EPersonaStateSnooze: state_str = "snooze"; break;
case k_EPersonaStateLookingToTrade: state_str = "trade"; break;
case k_EPersonaStateLookingToPlay: state_str = "play"; break;
default: state_str = "unknown"; break;
}
return JS_NewString(js, state_str);
)
JSC_CCALL(friends_count,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
int flags = k_EFriendFlagImmediate;
if (argc > 0) {
JS_ToInt32(js, &flags, argv[0]);
}
int count = SteamAPI_ISteamFriends_GetFriendCount(steam_friends, flags);
return JS_NewInt32(js, count);
)
JSC_CCALL(friends_get_friend,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
int index;
JS_ToInt32(js, &index, argv[0]);
int flags = k_EFriendFlagImmediate;
if (argc > 1) {
JS_ToInt32(js, &flags, argv[1]);
}
uint64_steamid friendID = SteamAPI_ISteamFriends_GetFriendByIndex(steam_friends, index, flags);
if (friendID == 0) return JS_NULL;
return steamid2js(js, friendID);
)
JSC_CCALL(friends_get_friend_name,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
uint64_steamid friendID;
if (argc > 0 && JS_IsObject(argv[0])) {
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "Expected SteamID");
friendID = sid->id;
} else {
double val;
JS_ToFloat64(js, &val, argv[0]);
friendID = (uint64_steamid)val;
}
const char *name = SteamAPI_ISteamFriends_GetFriendPersonaName(steam_friends, friendID);
return JS_NewString(js, name ? name : "");
)
JSC_CCALL(friends_activate_overlay,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
const char *dialog = JS_ToCString(js, argv[0]);
if (!dialog) return JS_EXCEPTION;
SteamAPI_ISteamFriends_ActivateGameOverlay(steam_friends, dialog);
JS_FreeCString(js, dialog);
return JS_NULL;
)
JSC_CCALL(friends_activate_overlay_to_user,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
const char *dialog = JS_ToCString(js, argv[0]);
if (!dialog) return JS_EXCEPTION;
uint64_steamid userID;
if (argc > 1 && JS_IsObject(argv[1])) {
steamid_t *sid = js2steamid(js, argv[1]);
if (!sid) {
JS_FreeCString(js, dialog);
return JS_ThrowTypeError(js, "Expected SteamID");
}
userID = sid->id;
} else {
double val;
JS_ToFloat64(js, &val, argv[1]);
userID = (uint64_steamid)val;
}
SteamAPI_ISteamFriends_ActivateGameOverlayToUser(steam_friends, dialog, userID);
JS_FreeCString(js, dialog);
return JS_NULL;
)
JSC_CCALL(friends_activate_overlay_to_web,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
const char *url = JS_ToCString(js, argv[0]);
if (!url) return JS_EXCEPTION;
SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage(steam_friends, url, k_EActivateGameOverlayToWebPageMode_Default);
JS_FreeCString(js, url);
return JS_NULL;
)
JSC_CCALL(friends_set_rich_presence,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
const char *key = JS_ToCString(js, argv[0]);
if (!key) return JS_EXCEPTION;
const char *value = JS_ToCString(js, argv[1]);
if (!value) {
JS_FreeCString(js, key);
return JS_EXCEPTION;
}
bool success = SteamAPI_ISteamFriends_SetRichPresence(steam_friends, key, value);
JS_FreeCString(js, key);
JS_FreeCString(js, value);
return JS_NewBool(js, success);
)
JSC_CCALL(friends_clear_rich_presence,
if (!steam_friends) return JS_ThrowInternalError(js, "Steam friends not initialized");
SteamAPI_ISteamFriends_ClearRichPresence(steam_friends);
return JS_NULL;
)
// CLOUD STORAGE
JSC_CCALL(cloud_enabled_app,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
bool enabled = SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(steam_remote);
return JS_NewBool(js, enabled);
)
JSC_CCALL(cloud_enabled_account,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
bool enabled = SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(steam_remote);
return JS_NewBool(js, enabled);
)
JSC_CCALL(cloud_enable,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
bool enable = JS_ToBool(js, argv[0]);
SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp(steam_remote, enable);
return JS_NULL;
)
JSC_CCALL(cloud_quota,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
uint64 total, available;
bool success = SteamAPI_ISteamRemoteStorage_GetQuota(steam_remote, &total, &available);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "total", JS_NewFloat64(js, (double)total));
JS_SetPropertyStr(js, obj, "available", JS_NewFloat64(js, (double)available));
return obj;
)
JSC_CCALL(cloud_write,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
size_t data_len;
uint8_t *data = NULL;
if (JS_IsString(argv[1])) {
const char *str = JS_ToCStringLen(js, &data_len, argv[1]);
if (!str) {
JS_FreeCString(js, filename);
return JS_EXCEPTION;
}
data = (uint8_t*)str;
} else {
data = (uint8_t*)js_get_blob_data(js, &data_len, argv[1]);
if (!data) {
JS_FreeCString(js, filename);
return JS_ThrowTypeError(js, "Second argument must be string or ArrayBuffer");
}
}
bool success = SteamAPI_ISteamRemoteStorage_FileWrite(steam_remote, filename, data, data_len);
if (JS_IsString(argv[1])) {
JS_FreeCString(js, (const char*)data);
}
JS_FreeCString(js, filename);
return JS_NewBool(js, success);
)
JSC_CCALL(cloud_read,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
int32 size = SteamAPI_ISteamRemoteStorage_GetFileSize(steam_remote, filename);
if (size <= 0) {
JS_FreeCString(js, filename);
return JS_NULL;
}
uint8_t *buffer = (uint8_t*)js_malloc(js, size);
if (!buffer) {
JS_FreeCString(js, filename);
return JS_EXCEPTION;
}
int32 read = SteamAPI_ISteamRemoteStorage_FileRead(steam_remote, filename, buffer, size);
JS_FreeCString(js, filename);
if (read != size) {
js_free(js, buffer);
return JS_NULL;
}
JSValue result = js_new_blob_stoned_copy(js, buffer, size);
js_free(js, buffer);
return result;
)
JSC_CCALL(cloud_delete,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
bool success = SteamAPI_ISteamRemoteStorage_FileDelete(steam_remote, filename);
JS_FreeCString(js, filename);
return JS_NewBool(js, success);
)
JSC_CCALL(cloud_exists,
if (!steam_remote) return JS_ThrowInternalError(js, "Steam remote storage not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
bool exists = SteamAPI_ISteamRemoteStorage_FileExists(steam_remote, filename);
JS_FreeCString(js, filename);
return JS_NewBool(js, exists);
)
// EXPANDED STEAM UTILS
JSC_CCALL(utils_overlay_enabled,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool enabled = SteamAPI_ISteamUtils_IsOverlayEnabled(steam_utils);
return JS_NewBool(js, enabled);
)
JSC_CCALL(utils_big_picture_mode,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool bigPicture = SteamAPI_ISteamUtils_IsSteamInBigPictureMode(steam_utils);
return JS_NewBool(js, bigPicture);
)
JSC_CCALL(utils_vr_mode,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool vrMode = SteamAPI_ISteamUtils_IsSteamRunningInVR(steam_utils);
return JS_NewBool(js, vrMode);
)
JSC_CCALL(utils_steam_deck,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool steamDeck = SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck(steam_utils);
return JS_NewBool(js, steamDeck);
)
JSC_CCALL(utils_battery_power,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint8 battery = SteamAPI_ISteamUtils_GetCurrentBatteryPower(steam_utils);
return JS_NewUint32(js, battery);
)
JSC_CCALL(utils_seconds_since_app_active,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 seconds = SteamAPI_ISteamUtils_GetSecondsSinceAppActive(steam_utils);
return JS_NewUint32(js, seconds);
)
JSC_CCALL(utils_ip_country,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
const char *country = SteamAPI_ISteamUtils_GetIPCountry(steam_utils);
return JS_NewString(js, country ? country : "");
)
JSC_CCALL(utils_ui_language,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
const char *language = SteamAPI_ISteamUtils_GetSteamUILanguage(steam_utils);
return JS_NewString(js, language ? language : "english");
)
JSC_CCALL(utils_get_seconds_since_computer_active,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 seconds = SteamAPI_ISteamUtils_GetSecondsSinceComputerActive(steam_utils);
return JS_NewUint32(js, seconds);
)
JSC_CCALL(utils_get_connected_universe,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
EUniverse universe = SteamAPI_ISteamUtils_GetConnectedUniverse(steam_utils);
return JS_NewUint32(js, universe);
)
JSC_CCALL(utils_get_server_real_time,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 server_time = SteamAPI_ISteamUtils_GetServerRealTime(steam_utils);
return JS_NewUint32(js, server_time);
)
JSC_CCALL(utils_get_image_size,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
int image_handle;
JS_ToInt32(js, &image_handle, argv[0]);
uint32 width, height;
bool success = SteamAPI_ISteamUtils_GetImageSize(steam_utils, image_handle, &width, &height);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "width", JS_NewUint32(js, width));
JS_SetPropertyStr(js, obj, "height", JS_NewUint32(js, height));
return obj;
)
JSC_CCALL(utils_get_image_rgba,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
int image_handle;
JS_ToInt32(js, &image_handle, argv[0]);
// First get the image size to allocate buffer
uint32 width, height;
if (!SteamAPI_ISteamUtils_GetImageSize(steam_utils, image_handle, &width, &height)) {
return JS_NULL;
}
uint32 buffer_size = width * height * 4; // RGBA = 4 bytes per pixel
uint8_t *buffer = (uint8_t*)js_malloc(js, buffer_size);
if (!buffer) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUtils_GetImageRGBA(steam_utils, image_handle, buffer, buffer_size);
if (!success) {
js_free(js, buffer);
return JS_NULL;
}
JSValue result = js_new_blob_stoned_copy(js, buffer, buffer_size);
js_free(js, buffer);
return result;
)
JSC_CCALL(utils_set_overlay_notification_position,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 position;
JS_ToUint32(js, &position, argv[0]);
SteamAPI_ISteamUtils_SetOverlayNotificationPosition(steam_utils, (ENotificationPosition)position);
return JS_NULL;
)
JSC_CCALL(utils_is_api_call_completed,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
double call_double;
JS_ToFloat64(js, &call_double, argv[0]);
SteamAPICall_t call = (SteamAPICall_t)call_double;
bool failed;
bool completed = SteamAPI_ISteamUtils_IsAPICallCompleted(steam_utils, call, &failed);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "completed", JS_NewBool(js, completed));
JS_SetPropertyStr(js, obj, "failed", JS_NewBool(js, failed));
return obj;
)
JSC_CCALL(utils_get_api_call_failure_reason,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
double call_double;
JS_ToFloat64(js, &call_double, argv[0]);
SteamAPICall_t call = (SteamAPICall_t)call_double;
ESteamAPICallFailure reason = SteamAPI_ISteamUtils_GetAPICallFailureReason(steam_utils, call);
return JS_NewUint32(js, reason);
)
JSC_CCALL(utils_get_ipc_call_count,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 count = SteamAPI_ISteamUtils_GetIPCCallCount(steam_utils);
return JS_NewUint32(js, count);
)
JSC_CCALL(utils_overlay_needs_present,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool needs_present = SteamAPI_ISteamUtils_BOverlayNeedsPresent(steam_utils);
return JS_NewBool(js, needs_present);
)
JSC_CCALL(utils_check_file_signature,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
SteamAPICall_t call = SteamAPI_ISteamUtils_CheckFileSignature(steam_utils, filename);
JS_FreeCString(js, filename);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(utils_show_gamepad_text_input,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 input_mode, line_mode, char_max;
JS_ToUint32(js, &input_mode, argv[0]);
JS_ToUint32(js, &line_mode, argv[1]);
const char *description = JS_ToCString(js, argv[2]);
if (!description) return JS_EXCEPTION;
JS_ToUint32(js, &char_max, argv[3]);
const char *existing_text = argc > 4 ? JS_ToCString(js, argv[4]) : "";
bool success = SteamAPI_ISteamUtils_ShowGamepadTextInput(steam_utils, (EGamepadTextInputMode)input_mode, (EGamepadTextInputLineMode)line_mode, description, char_max, existing_text);
JS_FreeCString(js, description);
if (argc > 4) JS_FreeCString(js, existing_text);
return JS_NewBool(js, success);
)
JSC_CCALL(utils_get_entered_gamepad_text_length,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 length = SteamAPI_ISteamUtils_GetEnteredGamepadTextLength(steam_utils);
return JS_NewUint32(js, length);
)
JSC_CCALL(utils_get_entered_gamepad_text_input,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 length = SteamAPI_ISteamUtils_GetEnteredGamepadTextLength(steam_utils);
if (length == 0) return JS_NewString(js, "");
char *buffer = (char*)js_malloc(js, length + 1);
if (!buffer) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUtils_GetEnteredGamepadTextInput(steam_utils, buffer, length + 1);
if (!success) {
js_free(js, buffer);
return JS_NewString(js, "");
}
JSValue result = JS_NewString(js, buffer);
js_free(js, buffer);
return result;
)
JSC_CCALL(utils_set_overlay_notification_inset,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
int horizontal_inset, vertical_inset;
JS_ToInt32(js, &horizontal_inset, argv[0]);
JS_ToInt32(js, &vertical_inset, argv[1]);
SteamAPI_ISteamUtils_SetOverlayNotificationInset(steam_utils, horizontal_inset, vertical_inset);
return JS_NULL;
)
JSC_CCALL(utils_start_vr_dashboard,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
SteamAPI_ISteamUtils_StartVRDashboard(steam_utils);
return JS_NULL;
)
JSC_CCALL(utils_is_vr_headset_streaming_enabled,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool enabled = SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled(steam_utils);
return JS_NewBool(js, enabled);
)
JSC_CCALL(utils_set_vr_headset_streaming_enabled,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool enabled = JS_ToBool(js, argv[0]);
SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled(steam_utils, enabled);
return JS_NULL;
)
JSC_CCALL(utils_is_steam_china_launcher,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool is_china = SteamAPI_ISteamUtils_IsSteamChinaLauncher(steam_utils);
return JS_NewBool(js, is_china);
)
JSC_CCALL(utils_init_filter_text,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 filter_options;
JS_ToUint32(js, &filter_options, argv[0]);
bool success = SteamAPI_ISteamUtils_InitFilterText(steam_utils, filter_options);
return JS_NewBool(js, success);
)
JSC_CCALL(utils_filter_text,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 context;
JS_ToUint32(js, &context, argv[0]);
steamid_t *sid = js2steamid(js, argv[1]);
if (!sid) return JS_ThrowTypeError(js, "Second argument must be a SteamID");
const char *input_message = JS_ToCString(js, argv[2]);
if (!input_message) return JS_EXCEPTION;
// Allocate buffer for filtered text (same size as input should be sufficient)
size_t input_len = strlen(input_message);
uint32 buffer_size = input_len + 1;
char *filtered_buffer = (char*)js_malloc(js, buffer_size);
if (!filtered_buffer) {
JS_FreeCString(js, input_message);
return JS_EXCEPTION;
}
int result = SteamAPI_ISteamUtils_FilterText(steam_utils, (ETextFilteringContext)context, sid->id, input_message, filtered_buffer, buffer_size);
JS_FreeCString(js, input_message);
if (result < 0) {
js_free(js, filtered_buffer);
return JS_NULL;
}
JSValue js_result = JS_NewString(js, filtered_buffer);
js_free(js, filtered_buffer);
return js_result;
)
JSC_CCALL(utils_get_ipv6_connectivity_state,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 protocol;
JS_ToUint32(js, &protocol, argv[0]);
ESteamIPv6ConnectivityState state = SteamAPI_ISteamUtils_GetIPv6ConnectivityState(steam_utils, (ESteamIPv6ConnectivityProtocol)protocol);
return JS_NewUint32(js, state);
)
JSC_CCALL(utils_show_floating_gamepad_text_input,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
uint32 keyboard_mode;
int x_pos, y_pos, width, height;
JS_ToUint32(js, &keyboard_mode, argv[0]);
JS_ToInt32(js, &x_pos, argv[1]);
JS_ToInt32(js, &y_pos, argv[2]);
JS_ToInt32(js, &width, argv[3]);
JS_ToInt32(js, &height, argv[4]);
bool success = SteamAPI_ISteamUtils_ShowFloatingGamepadTextInput(steam_utils, (EFloatingGamepadTextInputMode)keyboard_mode, x_pos, y_pos, width, height);
return JS_NewBool(js, success);
)
JSC_CCALL(utils_set_game_launcher_mode,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool launcher_mode = JS_ToBool(js, argv[0]);
SteamAPI_ISteamUtils_SetGameLauncherMode(steam_utils, launcher_mode);
return JS_NULL;
)
JSC_CCALL(utils_dismiss_floating_gamepad_text_input,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool success = SteamAPI_ISteamUtils_DismissFloatingGamepadTextInput(steam_utils);
return JS_NewBool(js, success);
)
JSC_CCALL(utils_dismiss_gamepad_text_input,
if (!steam_utils) return JS_ThrowInternalError(js, "Steam utils not initialized");
bool success = SteamAPI_ISteamUtils_DismissGamepadTextInput(steam_utils);
return JS_NewBool(js, success);
)
// SCREENSHOTS API
JSC_CCALL(screenshots_write,
if (!steam_screenshots) return JS_ThrowInternalError(js, "Steam screenshots not initialized");
const char *filename = JS_ToCString(js, argv[0]);
if (!filename) return JS_EXCEPTION;
uint32 width, height;
JS_ToUint32(js, &width, argv[1]);
JS_ToUint32(js, &height, argv[2]);
// Get image data from ArrayBuffer
size_t data_len;
uint8_t *data = (uint8_t*)js_get_blob_data(js, &data_len, argv[3]);
if (!data) {
JS_FreeCString(js, filename);
return JS_ThrowTypeError(js, "Fourth argument must be ArrayBuffer containing RGB data");
}
ScreenshotHandle handle = SteamAPI_ISteamScreenshots_WriteScreenshot(steam_screenshots, data, data_len, width, height);
JS_FreeCString(js, filename);
return JS_NewUint32(js, handle);
)
JSC_CCALL(screenshots_trigger,
if (!steam_screenshots) return JS_ThrowInternalError(js, "Steam screenshots not initialized");
SteamAPI_ISteamScreenshots_TriggerScreenshot(steam_screenshots);
return JS_NULL;
)
// NETWORKING API
JSC_CCALL(networking_send_p2p,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
// Get SteamID
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
// Get data
size_t data_len;
uint8_t *data = (uint8_t*)js_get_blob_data(js, &data_len, argv[1]);
if (!data) return JS_ThrowTypeError(js, "Second argument must be ArrayBuffer");
// Get send type (optional, defaults to reliable)
EP2PSend send_type = k_EP2PSendReliable;
if (argc > 2) {
uint32_t type;
JS_ToUint32(js, &type, argv[2]);
send_type = (EP2PSend)type;
}
// Get channel (optional, defaults to 0)
int channel = 0;
if (argc > 3) {
JS_ToInt32(js, &channel, argv[3]);
}
bool success = SteamAPI_ISteamNetworking_SendP2PPacket(steam_networking, sid->id, data, data_len, send_type, channel);
return JS_NewBool(js, success);
)
JSC_CCALL(networking_read_p2p,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
// Get channel (optional, defaults to 0)
int channel = 0;
if (argc > 0) {
JS_ToInt32(js, &channel, argv[0]);
}
uint32 msg_size;
if (!SteamAPI_ISteamNetworking_IsP2PPacketAvailable(steam_networking, &msg_size, channel)) {
return JS_NULL; // No packet available
}
uint8_t *buffer = (uint8_t*)js_malloc(js, msg_size);
if (!buffer) return JS_EXCEPTION;
CSteamID remote_steamid;
uint32 bytes_read;
bool success = SteamAPI_ISteamNetworking_ReadP2PPacket(steam_networking, buffer, msg_size, &bytes_read, &remote_steamid, channel);
if (!success) {
js_free(js, buffer);
return JS_NULL;
}
JSValue result = JS_NewObject(js);
JSValue data_buffer = js_new_blob_stoned_copy(js, buffer, bytes_read);
JSValue steamid_obj = steamid2js(js, remote_steamid.ConvertToUint64());
JS_SetPropertyStr(js, result, "data", data_buffer);
JS_SetPropertyStr(js, result, "steamid", steamid_obj);
JS_SetPropertyStr(js, result, "size", JS_NewUint32(js, bytes_read));
js_free(js, buffer);
return result;
)
JSC_CCALL(networking_accept_p2p,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
bool success = SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(steam_networking, sid->id);
return JS_NewBool(js, success);
)
JSC_CCALL(networking_close_p2p,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
// Get channel (optional, defaults to 0)
int channel = 0;
if (argc > 1) {
JS_ToInt32(js, &channel, argv[1]);
}
bool success = SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(steam_networking, sid->id);
return JS_NewBool(js, success);
)
JSC_CCALL(networking_close_p2p_channel,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
int channel;
JS_ToInt32(js, &channel, argv[1]);
bool success = SteamAPI_ISteamNetworking_CloseP2PChannelWithUser(steam_networking, sid->id, channel);
return JS_NewBool(js, success);
)
JSC_CCALL(networking_p2p_session_state,
if (!steam_networking) return JS_ThrowInternalError(js, "Steam networking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
P2PSessionState_t state;
if (!SteamAPI_ISteamNetworking_GetP2PSessionState(steam_networking, sid->id, &state)) {
return JS_NULL;
}
JSValue result = JS_NewObject(js);
JS_SetPropertyStr(js, result, "connection_active", JS_NewBool(js, state.m_bConnectionActive));
JS_SetPropertyStr(js, result, "connecting", JS_NewBool(js, state.m_bConnecting));
JS_SetPropertyStr(js, result, "session_error", JS_NewUint32(js, state.m_eP2PSessionError));
JS_SetPropertyStr(js, result, "using_relay", JS_NewBool(js, state.m_bUsingRelay));
JS_SetPropertyStr(js, result, "bytes_queued_for_send", JS_NewInt32(js, state.m_nBytesQueuedForSend));
JS_SetPropertyStr(js, result, "packets_queued_for_send", JS_NewInt32(js, state.m_nPacketsQueuedForSend));
JS_SetPropertyStr(js, result, "remote_ip", JS_NewUint32(js, state.m_nRemoteIP));
JS_SetPropertyStr(js, result, "remote_port", JS_NewUint32(js, state.m_nRemotePort));
return result;
)
// MATCHMAKING API
JSC_CCALL(matchmaking_create_lobby,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
// Get lobby type (defaults to public)
ELobbyType lobby_type = k_ELobbyTypePublic;
if (argc > 0) {
uint32_t type;
JS_ToUint32(js, &type, argv[0]);
lobby_type = (ELobbyType)type;
}
// Get max members (defaults to 4)
int max_members = 4;
if (argc > 1) {
JS_ToInt32(js, &max_members, argv[1]);
}
SteamAPICall_t call = SteamAPI_ISteamMatchmaking_CreateLobby(steam_matchmaking, lobby_type, max_members);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(matchmaking_join_lobby,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
SteamAPICall_t call = SteamAPI_ISteamMatchmaking_JoinLobby(steam_matchmaking, sid->id);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(matchmaking_leave_lobby,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a SteamID");
SteamAPI_ISteamMatchmaking_LeaveLobby(steam_matchmaking, sid->id);
return JS_NULL;
)
JSC_CCALL(matchmaking_invite_user,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *lobby_sid = js2steamid(js, argv[0]);
if (!lobby_sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
steamid_t *user_sid = js2steamid(js, argv[1]);
if (!user_sid) return JS_ThrowTypeError(js, "Second argument must be a user SteamID");
bool success = SteamAPI_ISteamMatchmaking_InviteUserToLobby(steam_matchmaking, lobby_sid->id, user_sid->id);
return JS_NewBool(js, success);
)
JSC_CCALL(matchmaking_lobby_member_count,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
int count = SteamAPI_ISteamMatchmaking_GetNumLobbyMembers(steam_matchmaking, sid->id);
return JS_NewInt32(js, count);
)
JSC_CCALL(matchmaking_lobby_member_by_index,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
int index;
JS_ToInt32(js, &index, argv[1]);
uint64_steamid member = SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex(steam_matchmaking, sid->id, index);
return steamid2js(js, member);
)
JSC_CCALL(matchmaking_lobby_owner,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
uint64_steamid owner = SteamAPI_ISteamMatchmaking_GetLobbyOwner(steam_matchmaking, sid->id);
return steamid2js(js, owner);
)
JSC_CCALL(matchmaking_set_lobby_data,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
const char *key = JS_ToCString(js, argv[1]);
if (!key) return JS_EXCEPTION;
const char *value = JS_ToCString(js, argv[2]);
if (!value) {
JS_FreeCString(js, key);
return JS_EXCEPTION;
}
bool success = SteamAPI_ISteamMatchmaking_SetLobbyData(steam_matchmaking, sid->id, key, value);
JS_FreeCString(js, key);
JS_FreeCString(js, value);
return JS_NewBool(js, success);
)
JSC_CCALL(matchmaking_get_lobby_data,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
const char *key = JS_ToCString(js, argv[1]);
if (!key) return JS_EXCEPTION;
const char *value = SteamAPI_ISteamMatchmaking_GetLobbyData(steam_matchmaking, sid->id, key);
JS_FreeCString(js, key);
return JS_NewString(js, value ? value : "");
)
JSC_CCALL(matchmaking_set_lobby_member_data,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
const char *key = JS_ToCString(js, argv[1]);
if (!key) return JS_EXCEPTION;
const char *value = JS_ToCString(js, argv[2]);
if (!value) {
JS_FreeCString(js, key);
return JS_EXCEPTION;
}
SteamAPI_ISteamMatchmaking_SetLobbyMemberData(steam_matchmaking, sid->id, key, value);
JS_FreeCString(js, key);
JS_FreeCString(js, value);
return JS_NULL;
)
JSC_CCALL(matchmaking_get_lobby_member_data,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *lobby_sid = js2steamid(js, argv[0]);
if (!lobby_sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
steamid_t *user_sid = js2steamid(js, argv[1]);
if (!user_sid) return JS_ThrowTypeError(js, "Second argument must be a user SteamID");
const char *key = JS_ToCString(js, argv[2]);
if (!key) return JS_EXCEPTION;
const char *value = SteamAPI_ISteamMatchmaking_GetLobbyMemberData(steam_matchmaking, lobby_sid->id, user_sid->id, key);
JS_FreeCString(js, key);
return JS_NewString(js, value ? value : "");
)
JSC_CCALL(matchmaking_send_lobby_chat_msg,
if (!steam_matchmaking) return JS_ThrowInternalError(js, "Steam matchmaking not initialized");
steamid_t *sid = js2steamid(js, argv[0]);
if (!sid) return JS_ThrowTypeError(js, "First argument must be a lobby SteamID");
size_t msg_len;
const char *message = JS_ToCStringLen(js, &msg_len, argv[1]);
if (!message) return JS_EXCEPTION;
bool success = SteamAPI_ISteamMatchmaking_SendLobbyChatMsg(steam_matchmaking, sid->id, message, msg_len);
JS_FreeCString(js, message);
return JS_NewBool(js, success);
)
// UGC (User Generated Content) API
JSC_CCALL(ugc_create_query_user_ugc_request,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
uint32 account_id, list_type, matching_type, sort_order, creator_app_id, consumer_app_id, page;
JS_ToUint32(js, &account_id, argv[0]);
JS_ToUint32(js, &list_type, argv[1]);
JS_ToUint32(js, &matching_type, argv[2]);
JS_ToUint32(js, &sort_order, argv[3]);
JS_ToUint32(js, &creator_app_id, argv[4]);
JS_ToUint32(js, &consumer_app_id, argv[5]);
JS_ToUint32(js, &page, argv[6]);
UGCQueryHandle_t handle = SteamAPI_ISteamUGC_CreateQueryUserUGCRequest(steam_ugc, account_id, (EUserUGCList)list_type, (EUGCMatchingUGCType)matching_type, (EUserUGCListSortOrder)sort_order, creator_app_id, consumer_app_id, page);
return JS_NewFloat64(js, (double)handle);
)
JSC_CCALL(ugc_create_query_all_ugc_request_page,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
uint32 query_type, matching_type, creator_app_id, consumer_app_id, page;
JS_ToUint32(js, &query_type, argv[0]);
JS_ToUint32(js, &matching_type, argv[1]);
JS_ToUint32(js, &creator_app_id, argv[2]);
JS_ToUint32(js, &consumer_app_id, argv[3]);
JS_ToUint32(js, &page, argv[4]);
UGCQueryHandle_t handle = SteamAPI_ISteamUGC_CreateQueryAllUGCRequestPage(steam_ugc, (EUGCQuery)query_type, (EUGCMatchingUGCType)matching_type, creator_app_id, consumer_app_id, page);
return JS_NewFloat64(js, (double)handle);
)
JSC_CCALL(ugc_create_query_ugc_details_request,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
// Get array of published file IDs
if (!JS_IsArray(js, argv[0])) return JS_ThrowTypeError(js, "First argument must be an array of published file IDs");
JSValue length_val = JS_GetPropertyStr(js, argv[0], "length");
uint32 num_ids;
JS_ToUint32(js, &num_ids, length_val);
JS_FreeValue(js, length_val);
if (num_ids == 0) return JS_ThrowRangeError(js, "Array must contain at least one published file ID");
PublishedFileId_t *file_ids = (PublishedFileId_t*)js_malloc(js, sizeof(PublishedFileId_t) * num_ids);
if (!file_ids) return JS_EXCEPTION;
for (uint32 i = 0; i < num_ids; i++) {
JSValue id_val = JS_GetPropertyUint32(js, argv[0], i);
double id_double;
JS_ToFloat64(js, &id_double, id_val);
file_ids[i] = (PublishedFileId_t)id_double;
JS_FreeValue(js, id_val);
}
UGCQueryHandle_t handle = SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest(steam_ugc, file_ids, num_ids);
js_free(js, file_ids);
return JS_NewFloat64(js, (double)handle);
)
JSC_CCALL(ugc_send_query_ugc_request,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
SteamAPICall_t call = SteamAPI_ISteamUGC_SendQueryUGCRequest(steam_ugc, handle);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(ugc_release_query_ugc_request,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
bool success = SteamAPI_ISteamUGC_ReleaseQueryUGCRequest(steam_ugc, handle);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_add_required_tag,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
const char *tag = JS_ToCString(js, argv[1]);
if (!tag) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_AddRequiredTag(steam_ugc, handle, tag);
JS_FreeCString(js, tag);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_add_excluded_tag,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
const char *tag = JS_ToCString(js, argv[1]);
if (!tag) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_AddExcludedTag(steam_ugc, handle, tag);
JS_FreeCString(js, tag);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_set_search_text,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
const char *search_text = JS_ToCString(js, argv[1]);
if (!search_text) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetSearchText(steam_ugc, handle, search_text);
JS_FreeCString(js, search_text);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_set_language,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCQueryHandle_t handle = (UGCQueryHandle_t)handle_double;
const char *language = JS_ToCString(js, argv[1]);
if (!language) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetLanguage(steam_ugc, handle, language);
JS_FreeCString(js, language);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_subscribe_item,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
SteamAPICall_t call = SteamAPI_ISteamUGC_SubscribeItem(steam_ugc, (PublishedFileId_t)file_id);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(ugc_unsubscribe_item,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
SteamAPICall_t call = SteamAPI_ISteamUGC_UnsubscribeItem(steam_ugc, (PublishedFileId_t)file_id);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(ugc_get_num_subscribed_items,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
bool include_locally_disabled = argc > 0 ? JS_ToBool(js, argv[0]) : false;
uint32 count = SteamAPI_ISteamUGC_GetNumSubscribedItems(steam_ugc, include_locally_disabled);
return JS_NewUint32(js, count);
)
JSC_CCALL(ugc_get_subscribed_items,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
uint32 max_entries;
JS_ToUint32(js, &max_entries, argv[0]);
bool include_locally_disabled = argc > 1 ? JS_ToBool(js, argv[1]) : false;
if (max_entries == 0) return JS_NewArray(js);
PublishedFileId_t *file_ids = (PublishedFileId_t*)js_malloc(js, sizeof(PublishedFileId_t) * max_entries);
if (!file_ids) return JS_EXCEPTION;
uint32 actual_count = SteamAPI_ISteamUGC_GetSubscribedItems(steam_ugc, file_ids, max_entries, include_locally_disabled);
JSValue result = JS_NewArray(js);
for (uint32 i = 0; i < actual_count; i++) {
JS_SetPropertyUint32(js, result, i, JS_NewFloat64(js, (double)file_ids[i]));
}
js_free(js, file_ids);
return result;
)
JSC_CCALL(ugc_get_item_state,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
uint32 state = SteamAPI_ISteamUGC_GetItemState(steam_ugc, (PublishedFileId_t)file_id);
return JS_NewUint32(js, state);
)
JSC_CCALL(ugc_get_item_install_info,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
uint64 size_on_disk;
char folder[1024];
uint32 timestamp;
bool success = SteamAPI_ISteamUGC_GetItemInstallInfo(steam_ugc, (PublishedFileId_t)file_id, &size_on_disk, folder, sizeof(folder), &timestamp);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "size_on_disk", JS_NewFloat64(js, (double)size_on_disk));
JS_SetPropertyStr(js, obj, "folder", JS_NewString(js, folder));
JS_SetPropertyStr(js, obj, "timestamp", JS_NewUint32(js, timestamp));
return obj;
)
JSC_CCALL(ugc_get_item_download_info,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
uint64 bytes_downloaded, bytes_total;
bool success = SteamAPI_ISteamUGC_GetItemDownloadInfo(steam_ugc, (PublishedFileId_t)file_id, &bytes_downloaded, &bytes_total);
if (!success) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "bytes_downloaded", JS_NewFloat64(js, (double)bytes_downloaded));
JS_SetPropertyStr(js, obj, "bytes_total", JS_NewFloat64(js, (double)bytes_total));
return obj;
)
JSC_CCALL(ugc_download_item,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double file_id;
JS_ToFloat64(js, &file_id, argv[0]);
bool high_priority = argc > 1 ? JS_ToBool(js, argv[1]) : false;
bool success = SteamAPI_ISteamUGC_DownloadItem(steam_ugc, (PublishedFileId_t)file_id, high_priority);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_create_item,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
uint32 consumer_app_id, file_type;
JS_ToUint32(js, &consumer_app_id, argv[0]);
JS_ToUint32(js, &file_type, argv[1]);
SteamAPICall_t call = SteamAPI_ISteamUGC_CreateItem(steam_ugc, consumer_app_id, (EWorkshopFileType)file_type);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(ugc_start_item_update,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
uint32 consumer_app_id;
double file_id;
JS_ToUint32(js, &consumer_app_id, argv[0]);
JS_ToFloat64(js, &file_id, argv[1]);
UGCUpdateHandle_t handle = SteamAPI_ISteamUGC_StartItemUpdate(steam_ugc, consumer_app_id, (PublishedFileId_t)file_id);
return JS_NewFloat64(js, (double)handle);
)
JSC_CCALL(ugc_set_item_title,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
const char *title = JS_ToCString(js, argv[1]);
if (!title) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetItemTitle(steam_ugc, handle, title);
JS_FreeCString(js, title);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_set_item_description,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
const char *description = JS_ToCString(js, argv[1]);
if (!description) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetItemDescription(steam_ugc, handle, description);
JS_FreeCString(js, description);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_set_item_content,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
const char *content_folder = JS_ToCString(js, argv[1]);
if (!content_folder) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetItemContent(steam_ugc, handle, content_folder);
JS_FreeCString(js, content_folder);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_set_item_preview,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
const char *preview_file = JS_ToCString(js, argv[1]);
if (!preview_file) return JS_EXCEPTION;
bool success = SteamAPI_ISteamUGC_SetItemPreview(steam_ugc, handle, preview_file);
JS_FreeCString(js, preview_file);
return JS_NewBool(js, success);
)
JSC_CCALL(ugc_submit_item_update,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
const char *change_note = argc > 1 ? JS_ToCString(js, argv[1]) : NULL;
SteamAPICall_t call = SteamAPI_ISteamUGC_SubmitItemUpdate(steam_ugc, handle, change_note);
if (change_note) JS_FreeCString(js, change_note);
return JS_NewFloat64(js, (double)call);
)
JSC_CCALL(ugc_get_item_update_progress,
if (!steam_ugc) return JS_ThrowInternalError(js, "Steam UGC not initialized");
double handle_double;
JS_ToFloat64(js, &handle_double, argv[0]);
UGCUpdateHandle_t handle = (UGCUpdateHandle_t)handle_double;
uint64 bytes_processed, bytes_total;
EItemUpdateStatus status = SteamAPI_ISteamUGC_GetItemUpdateProgress(steam_ugc, handle, &bytes_processed, &bytes_total);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "status", JS_NewUint32(js, status));
JS_SetPropertyStr(js, obj, "bytes_processed", JS_NewFloat64(js, (double)bytes_processed));
JS_SetPropertyStr(js, obj, "bytes_total", JS_NewFloat64(js, (double)bytes_total));
return obj;
)
// Function lists for sub-objects
static const JSCFunctionListEntry js_steam_stats_funcs[] = {
MIST_FUNC_DEF(stats, request, 0),
MIST_FUNC_DEF(stats, store, 0),
MIST_FUNC_DEF(stats, get_int, 1),
MIST_FUNC_DEF(stats, get_float, 1),
MIST_FUNC_DEF(stats, set_int, 2),
MIST_FUNC_DEF(stats, set_float, 2),
MIST_FUNC_DEF(stats, update_avg_rate, 3),
MIST_FUNC_DEF(stats, get_user_stat_int, 2),
MIST_FUNC_DEF(stats, get_user_stat_float, 2),
MIST_FUNC_DEF(stats, reset_all, 1),
MIST_FUNC_DEF(stats, get_number_of_current_players, 0),
MIST_FUNC_DEF(stats, request_global_achievement_percentages, 0),
MIST_FUNC_DEF(stats, request_global, 1),
MIST_FUNC_DEF(stats, get_global_stat_int64, 1),
MIST_FUNC_DEF(stats, get_global_stat_double, 1),
MIST_FUNC_DEF(stats, get_global_stat_history_int64, 1),
MIST_FUNC_DEF(stats, get_global_stat_history_double, 1),
};
static const JSCFunctionListEntry js_steam_achievement_funcs[] = {
MIST_FUNC_DEF(achievement, get, 1),
MIST_FUNC_DEF(achievement, set, 1),
MIST_FUNC_DEF(achievement, clear, 1),
MIST_FUNC_DEF(achievement, count, 0),
MIST_FUNC_DEF(achievement, name, 1),
MIST_FUNC_DEF(achievement, get_and_unlock_time, 1),
MIST_FUNC_DEF(achievement, get_icon, 1),
MIST_FUNC_DEF(achievement, get_display_attribute, 2),
MIST_FUNC_DEF(achievement, indicate_progress, 3),
MIST_FUNC_DEF(achievement, get_user_achievement, 2),
MIST_FUNC_DEF(achievement, get_user_achievement_and_unlock_time, 2),
MIST_FUNC_DEF(achievement, get_achieved_percent, 1),
MIST_FUNC_DEF(achievement, get_progress_limits_int, 1),
MIST_FUNC_DEF(achievement, get_progress_limits_float, 1),
MIST_FUNC_DEF(achievement, get_most_achieved_info, 0),
MIST_FUNC_DEF(achievement, get_next_most_achieved_info, 1),
};
static const JSCFunctionListEntry js_steam_leaderboard_funcs[] = {
MIST_FUNC_DEF(leaderboard, find_or_create, 3),
MIST_FUNC_DEF(leaderboard, find, 1),
MIST_FUNC_DEF(leaderboard, get_name, 1),
MIST_FUNC_DEF(leaderboard, get_entry_count, 1),
MIST_FUNC_DEF(leaderboard, get_sort_method, 1),
MIST_FUNC_DEF(leaderboard, get_display_type, 1),
MIST_FUNC_DEF(leaderboard, download_entries, 4),
MIST_FUNC_DEF(leaderboard, download_entries_for_users, 2),
MIST_FUNC_DEF(leaderboard, get_downloaded_entry, 2),
MIST_FUNC_DEF(leaderboard, upload_score, 3),
MIST_FUNC_DEF(leaderboard, attach_ugc, 2),
};
static const JSCFunctionListEntry js_steam_app_funcs[] = {
MIST_FUNC_DEF(app, id, 0),
MIST_FUNC_DEF(app, owner, 0),
MIST_FUNC_DEF(app, installed, 1),
MIST_FUNC_DEF(app, subscribed, 0),
MIST_FUNC_DEF(app, language, 0),
MIST_FUNC_DEF(app, dlc_installed, 1),
MIST_FUNC_DEF(app, is_low_violence, 0),
MIST_FUNC_DEF(app, is_cybercafe, 0),
MIST_FUNC_DEF(app, is_vac_banned, 0),
MIST_FUNC_DEF(app, available_languages, 0),
MIST_FUNC_DEF(app, is_subscribed_app, 1),
MIST_FUNC_DEF(app, earliest_purchase_time, 1),
MIST_FUNC_DEF(app, is_subscribed_from_free_weekend, 0),
MIST_FUNC_DEF(app, dlc_count, 0),
MIST_FUNC_DEF(app, get_dlc_data_by_index, 1),
MIST_FUNC_DEF(app, install_dlc, 1),
MIST_FUNC_DEF(app, uninstall_dlc, 1),
MIST_FUNC_DEF(app, request_proof_of_purchase_key, 1),
MIST_FUNC_DEF(app, get_current_beta_name, 0),
MIST_FUNC_DEF(app, mark_content_corrupt, 1),
MIST_FUNC_DEF(app, get_installed_depots, 1),
MIST_FUNC_DEF(app, get_install_dir, 1),
MIST_FUNC_DEF(app, get_launch_query_param, 1),
MIST_FUNC_DEF(app, get_dlc_download_progress, 1),
MIST_FUNC_DEF(app, get_build_id, 0),
MIST_FUNC_DEF(app, request_all_proof_of_purchase_keys, 0),
MIST_FUNC_DEF(app, get_file_details, 1),
MIST_FUNC_DEF(app, get_launch_command_line, 0),
MIST_FUNC_DEF(app, is_subscribed_from_family_sharing, 0),
MIST_FUNC_DEF(app, is_timed_trial, 0),
MIST_FUNC_DEF(app, set_dlc_context, 1),
MIST_FUNC_DEF(app, get_num_betas, 0),
MIST_FUNC_DEF(app, get_beta_info, 1),
MIST_FUNC_DEF(app, set_active_beta, 1),
};
static const JSCFunctionListEntry js_steam_user_funcs[] = {
MIST_FUNC_DEF(user, logged_on, 0),
MIST_FUNC_DEF(user, steam_id, 0),
MIST_FUNC_DEF(user, level, 0),
MIST_FUNC_DEF(user, hsteam_user, 0),
MIST_FUNC_DEF(user, get_user_data_folder, 0),
MIST_FUNC_DEF(user, start_voice_recording, 0),
MIST_FUNC_DEF(user, stop_voice_recording, 0),
MIST_FUNC_DEF(user, get_available_voice, 1),
MIST_FUNC_DEF(user, get_voice, 1),
MIST_FUNC_DEF(user, decompress_voice, 3),
MIST_FUNC_DEF(user, get_voice_optimal_sample_rate, 0),
MIST_FUNC_DEF(user, get_auth_session_ticket, 0),
MIST_FUNC_DEF(user, get_auth_ticket_for_web_api, 1),
MIST_FUNC_DEF(user, begin_auth_session, 2),
MIST_FUNC_DEF(user, end_auth_session, 1),
MIST_FUNC_DEF(user, cancel_auth_ticket, 1),
MIST_FUNC_DEF(user, has_license_for_app, 2),
MIST_FUNC_DEF(user, is_behind_nat, 0),
MIST_FUNC_DEF(user, advertise_game, 3),
MIST_FUNC_DEF(user, request_encrypted_app_ticket, 1),
MIST_FUNC_DEF(user, get_encrypted_app_ticket, 0),
MIST_FUNC_DEF(user, get_game_badge_level, 2),
MIST_FUNC_DEF(user, request_store_auth_url, 1),
MIST_FUNC_DEF(user, is_phone_verified, 0),
MIST_FUNC_DEF(user, is_two_factor_enabled, 0),
MIST_FUNC_DEF(user, is_phone_identifying, 0),
MIST_FUNC_DEF(user, is_phone_requiring_verification, 0),
MIST_FUNC_DEF(user, get_market_eligibility, 0),
MIST_FUNC_DEF(user, get_duration_control, 0),
MIST_FUNC_DEF(user, set_duration_control_online_state, 1),
MIST_FUNC_DEF(user, track_app_usage_event, 3),
MIST_FUNC_DEF(user, initiate_game_connection_deprecated, 4),
MIST_FUNC_DEF(user, terminate_game_connection_deprecated, 2),
};
static const JSCFunctionListEntry js_steam_friends_funcs[] = {
MIST_FUNC_DEF(friends, name, 0),
MIST_FUNC_DEF(friends, state, 0),
MIST_FUNC_DEF(friends, count, 1),
MIST_FUNC_DEF(friends, get_friend, 2),
MIST_FUNC_DEF(friends, get_friend_name, 1),
MIST_FUNC_DEF(friends, activate_overlay, 1),
MIST_FUNC_DEF(friends, activate_overlay_to_user, 2),
MIST_FUNC_DEF(friends, activate_overlay_to_web, 1),
MIST_FUNC_DEF(friends, set_rich_presence, 2),
MIST_FUNC_DEF(friends, clear_rich_presence, 0),
};
static const JSCFunctionListEntry js_steam_cloud_funcs[] = {
MIST_FUNC_DEF(cloud, enabled_app, 0),
MIST_FUNC_DEF(cloud, enabled_account, 0),
MIST_FUNC_DEF(cloud, enable, 1),
MIST_FUNC_DEF(cloud, quota, 0),
MIST_FUNC_DEF(cloud, write, 2),
MIST_FUNC_DEF(cloud, read, 1),
MIST_FUNC_DEF(cloud, delete, 1),
MIST_FUNC_DEF(cloud, exists, 1),
};
static const JSCFunctionListEntry js_steam_utils_funcs[] = {
MIST_FUNC_DEF(utils, overlay_enabled, 0),
MIST_FUNC_DEF(utils, big_picture_mode, 0),
MIST_FUNC_DEF(utils, vr_mode, 0),
MIST_FUNC_DEF(utils, steam_deck, 0),
MIST_FUNC_DEF(utils, battery_power, 0),
MIST_FUNC_DEF(utils, seconds_since_app_active, 0),
MIST_FUNC_DEF(utils, ip_country, 0),
MIST_FUNC_DEF(utils, ui_language, 0),
MIST_FUNC_DEF(utils, get_seconds_since_computer_active, 0),
MIST_FUNC_DEF(utils, get_connected_universe, 0),
MIST_FUNC_DEF(utils, get_server_real_time, 0),
MIST_FUNC_DEF(utils, get_image_size, 1),
MIST_FUNC_DEF(utils, get_image_rgba, 1),
MIST_FUNC_DEF(utils, set_overlay_notification_position, 1),
MIST_FUNC_DEF(utils, is_api_call_completed, 1),
MIST_FUNC_DEF(utils, get_api_call_failure_reason, 1),
MIST_FUNC_DEF(utils, get_ipc_call_count, 0),
MIST_FUNC_DEF(utils, overlay_needs_present, 0),
MIST_FUNC_DEF(utils, check_file_signature, 1),
MIST_FUNC_DEF(utils, show_gamepad_text_input, 5),
MIST_FUNC_DEF(utils, get_entered_gamepad_text_length, 0),
MIST_FUNC_DEF(utils, get_entered_gamepad_text_input, 0),
MIST_FUNC_DEF(utils, set_overlay_notification_inset, 2),
MIST_FUNC_DEF(utils, start_vr_dashboard, 0),
MIST_FUNC_DEF(utils, is_vr_headset_streaming_enabled, 0),
MIST_FUNC_DEF(utils, set_vr_headset_streaming_enabled, 1),
MIST_FUNC_DEF(utils, is_steam_china_launcher, 0),
MIST_FUNC_DEF(utils, init_filter_text, 1),
MIST_FUNC_DEF(utils, filter_text, 3),
MIST_FUNC_DEF(utils, get_ipv6_connectivity_state, 1),
MIST_FUNC_DEF(utils, show_floating_gamepad_text_input, 5),
MIST_FUNC_DEF(utils, set_game_launcher_mode, 1),
MIST_FUNC_DEF(utils, dismiss_floating_gamepad_text_input, 0),
MIST_FUNC_DEF(utils, dismiss_gamepad_text_input, 0),
};
static const JSCFunctionListEntry js_steam_screenshots_funcs[] = {
MIST_FUNC_DEF(screenshots, write, 4),
MIST_FUNC_DEF(screenshots, trigger, 0),
};
static const JSCFunctionListEntry js_steam_networking_funcs[] = {
MIST_FUNC_DEF(networking, send_p2p, 4),
MIST_FUNC_DEF(networking, read_p2p, 1),
MIST_FUNC_DEF(networking, accept_p2p, 1),
MIST_FUNC_DEF(networking, close_p2p, 2),
MIST_FUNC_DEF(networking, close_p2p_channel, 2),
MIST_FUNC_DEF(networking, p2p_session_state, 1),
};
static const JSCFunctionListEntry js_steam_matchmaking_funcs[] = {
MIST_FUNC_DEF(matchmaking, create_lobby, 2),
MIST_FUNC_DEF(matchmaking, join_lobby, 1),
MIST_FUNC_DEF(matchmaking, leave_lobby, 1),
MIST_FUNC_DEF(matchmaking, invite_user, 2),
MIST_FUNC_DEF(matchmaking, lobby_member_count, 1),
MIST_FUNC_DEF(matchmaking, lobby_member_by_index, 2),
MIST_FUNC_DEF(matchmaking, lobby_owner, 1),
MIST_FUNC_DEF(matchmaking, set_lobby_data, 3),
MIST_FUNC_DEF(matchmaking, get_lobby_data, 2),
MIST_FUNC_DEF(matchmaking, set_lobby_member_data, 3),
MIST_FUNC_DEF(matchmaking, get_lobby_member_data, 3),
MIST_FUNC_DEF(matchmaking, send_lobby_chat_msg, 2),
};
static const JSCFunctionListEntry js_steam_ugc_funcs[] = {
MIST_FUNC_DEF(ugc, create_query_user_ugc_request, 7),
MIST_FUNC_DEF(ugc, create_query_all_ugc_request_page, 5),
MIST_FUNC_DEF(ugc, create_query_ugc_details_request, 1),
MIST_FUNC_DEF(ugc, send_query_ugc_request, 1),
MIST_FUNC_DEF(ugc, release_query_ugc_request, 1),
MIST_FUNC_DEF(ugc, add_required_tag, 2),
MIST_FUNC_DEF(ugc, add_excluded_tag, 2),
MIST_FUNC_DEF(ugc, set_search_text, 2),
MIST_FUNC_DEF(ugc, set_language, 2),
MIST_FUNC_DEF(ugc, subscribe_item, 1),
MIST_FUNC_DEF(ugc, unsubscribe_item, 1),
MIST_FUNC_DEF(ugc, get_num_subscribed_items, 1),
MIST_FUNC_DEF(ugc, get_subscribed_items, 2),
MIST_FUNC_DEF(ugc, get_item_state, 1),
MIST_FUNC_DEF(ugc, get_item_install_info, 1),
MIST_FUNC_DEF(ugc, get_item_download_info, 1),
MIST_FUNC_DEF(ugc, download_item, 2),
MIST_FUNC_DEF(ugc, create_item, 2),
MIST_FUNC_DEF(ugc, start_item_update, 2),
MIST_FUNC_DEF(ugc, set_item_title, 2),
MIST_FUNC_DEF(ugc, set_item_description, 2),
MIST_FUNC_DEF(ugc, set_item_content, 2),
MIST_FUNC_DEF(ugc, set_item_preview, 2),
MIST_FUNC_DEF(ugc, submit_item_update, 2),
MIST_FUNC_DEF(ugc, get_item_update_progress, 1),
};
// Main Steam API functions
static const JSCFunctionListEntry js_steam_funcs[] = {
MIST_FUNC_DEF(steam, init, 0),
MIST_FUNC_DEF(steam, shutdown, 0),
MIST_FUNC_DEF(steam, run_callbacks, 0),
};
JSValue js_steam_use(JSContext *js) {
// Register SteamID class if not already done
static int steamid_class_initialized = 0;
if (!steamid_class_initialized) {
JS_NewClassID(&js_steamid_id);
JS_NewClass(JS_GetRuntime(js), js_steamid_id, &js_steamid_class);
JSValue steamid_proto = JS_NewObject(js);
JS_SetPropertyFunctionList(js, steamid_proto, js_steamid_proto_funcs, countof(js_steamid_proto_funcs));
JS_SetClassProto(js, js_steamid_id, steamid_proto);
steamid_class_initialized = 1;
}
JSValue steam = JS_NewObject(js);
JS_SetPropertyFunctionList(js, steam, js_steam_funcs, countof(js_steam_funcs));
// Stats sub-object
JSValue stats = JS_NewObject(js);
JS_SetPropertyFunctionList(js, stats, js_steam_stats_funcs, countof(js_steam_stats_funcs));
JS_SetPropertyStr(js, steam, "stats", stats);
// Achievement sub-object
JSValue achievement = JS_NewObject(js);
JS_SetPropertyFunctionList(js, achievement, js_steam_achievement_funcs, countof(js_steam_achievement_funcs));
JS_SetPropertyStr(js, steam, "achievement", achievement);
// Leaderboard sub-object
JSValue leaderboard = JS_NewObject(js);
JS_SetPropertyFunctionList(js, leaderboard, js_steam_leaderboard_funcs, countof(js_steam_leaderboard_funcs));
JS_SetPropertyStr(js, steam, "leaderboard", leaderboard);
// App sub-object
JSValue app = JS_NewObject(js);
JS_SetPropertyFunctionList(js, app, js_steam_app_funcs, countof(js_steam_app_funcs));
JS_SetPropertyStr(js, steam, "app", app);
// User sub-object
JSValue user = JS_NewObject(js);
JS_SetPropertyFunctionList(js, user, js_steam_user_funcs, countof(js_steam_user_funcs));
JS_SetPropertyStr(js, steam, "user", user);
// Friends sub-object
JSValue friends = JS_NewObject(js);
JS_SetPropertyFunctionList(js, friends, js_steam_friends_funcs, countof(js_steam_friends_funcs));
JS_SetPropertyStr(js, steam, "friends", friends);
// Cloud sub-object
JSValue cloud = JS_NewObject(js);
JS_SetPropertyFunctionList(js, cloud, js_steam_cloud_funcs, countof(js_steam_cloud_funcs));
JS_SetPropertyStr(js, steam, "cloud", cloud);
// Utils sub-object
JSValue utils = JS_NewObject(js);
JS_SetPropertyFunctionList(js, utils, js_steam_utils_funcs, countof(js_steam_utils_funcs));
JS_SetPropertyStr(js, steam, "utils", utils);
// Screenshots sub-object
JSValue screenshots = JS_NewObject(js);
JS_SetPropertyFunctionList(js, screenshots, js_steam_screenshots_funcs, countof(js_steam_screenshots_funcs));
JS_SetPropertyStr(js, steam, "screenshots", screenshots);
// Networking sub-object
JSValue networking = JS_NewObject(js);
JS_SetPropertyFunctionList(js, networking, js_steam_networking_funcs, countof(js_steam_networking_funcs));
JS_SetPropertyStr(js, steam, "networking", networking);
// Matchmaking sub-object
JSValue matchmaking = JS_NewObject(js);
JS_SetPropertyFunctionList(js, matchmaking, js_steam_matchmaking_funcs, countof(js_steam_matchmaking_funcs));
JS_SetPropertyStr(js, steam, "matchmaking", matchmaking);
// UGC sub-object
JSValue ugc = JS_NewObject(js);
JS_SetPropertyFunctionList(js, ugc, js_steam_ugc_funcs, countof(js_steam_ugc_funcs));
JS_SetPropertyStr(js, steam, "ugc", ugc);
return steam;
}
} // extern "C"