diff --git a/.gitignore b/.gitignore index 496ee2c..0e2d13a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.DS_Store \ No newline at end of file +.DS_Store +sdk/ +*.dylib +*.o \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index b9e1de2..0000000 --- a/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -def: - c++ -fPIC -shared qjs_steam.cpp -Isdk/public -I../cell/source -Lsdk/redistributable_bin/osx -lsteam_api -lcell -o steam.dylib \ No newline at end of file diff --git a/qjs_steam.cpp b/steam.cpp similarity index 98% rename from qjs_steam.cpp rename to steam.cpp index 4dc6538..f59d315 100644 --- a/qjs_steam.cpp +++ b/steam.cpp @@ -77,32 +77,25 @@ 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); - } +JSValue steam_init(JSContext *js) { + SteamErrMsg errMsg; + ESteamAPIInitResult init_result = SteamAPI_InitFlat(&errMsg); - 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)"); + if (init_result != k_ESteamAPIInitResult_OK) { + switch (init_result) { + case k_ESteamAPIInitResult_NoSteamClient: + return JS_ThrowInternalError(js, "Failed to initialize Steam: Steam client is not running or not logged in - %s", errMsg); + + case k_ESteamAPIInitResult_VersionMismatch: + return JS_ThrowInternalError(js, "Failed to initialize Steam: Steam client version is out of date - %s", errMsg); + + case k_ESteamAPIInitResult_FailedGeneric: + default: + return JS_ThrowInternalError(js, "Failed to initialize Steam: %s", errMsg); + } } // Get interface pointers - must be called after SteamAPI_InitFlat succeeds @@ -124,45 +117,31 @@ JSC_CCALL(steam_init, // 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(); - } + SteamAPI_RunCallbacks(); return JS_NULL; ) @@ -1247,6 +1226,7 @@ JSC_CCALL(user_decompress_voice, size_t compressed_size; void *compressed_data = js_get_blob_data(js, &compressed_size, argv[0]); + if (compressed_data == (void*)-1) return JS_EXCEPTION; if (!compressed_data) return JS_ThrowTypeError(js, "First argument must be a blob"); uint32 dest_buffer_size = 22050 * 2; @@ -1320,6 +1300,7 @@ JSC_CCALL(user_begin_auth_session, size_t ticket_size; void *ticket_data = js_get_blob_data(js, &ticket_size, argv[0]); + if (ticket_data == (void*)-1) return JS_EXCEPTION; if (!ticket_data) return JS_ThrowTypeError(js, "First argument must be a blob"); steamid_t *sid = js2steamid(js, argv[1]); @@ -1391,6 +1372,7 @@ JSC_CCALL(user_request_encrypted_app_ticket, if (argc > 0 && !JS_IsNull(argv[0])) { data = js_get_blob_data(js, &data_size, argv[0]); + if (data == (void*)-1) return JS_EXCEPTION; if (!data) return JS_ThrowTypeError(js, "First argument must be a blob or null"); } @@ -1752,6 +1734,10 @@ JSC_CCALL(cloud_write, data = (uint8_t*)str; } else { data = (uint8_t*)js_get_blob_data(js, &data_len, argv[1]); + if (data == (uint8_t*)-1) { + JS_FreeCString(js, filename); + return JS_EXCEPTION; + } if (!data) { JS_FreeCString(js, filename); return JS_ThrowTypeError(js, "Second argument must be string or ArrayBuffer"); @@ -2205,6 +2191,10 @@ JSC_CCALL(screenshots_write, // 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 == (uint8_t*)-1) { + JS_FreeCString(js, filename); + return JS_EXCEPTION; + } if (!data) { JS_FreeCString(js, filename); return JS_ThrowTypeError(js, "Fourth argument must be ArrayBuffer containing RGB data"); @@ -2234,6 +2224,7 @@ JSC_CCALL(networking_send_p2p, // Get data size_t data_len; uint8_t *data = (uint8_t*)js_get_blob_data(js, &data_len, argv[1]); + if (data == (uint8_t*)-1) return JS_EXCEPTION; if (!data) return JS_ThrowTypeError(js, "Second argument must be ArrayBuffer"); // Get send type (optional, defaults to reliable) @@ -3167,12 +3158,10 @@ static const JSCFunctionListEntry js_steam_ugc_funcs[] = { // 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) { +CELL_USE_INIT( // Register SteamID class if not already done static int steamid_class_initialized = 0; if (!steamid_class_initialized) { @@ -3248,8 +3237,13 @@ JSValue js_steam_use(JSContext *js) { JSValue ugc = JS_NewObject(js); JS_SetPropertyFunctionList(js, ugc, js_steam_ugc_funcs, countof(js_steam_ugc_funcs)); JS_SetPropertyStr(js, steam, "ugc", ugc); - + + JSValue ret = steam_init(js); + + if (JS_HasException(js)) + return ret; + return steam; -} +) } // extern "C" \ No newline at end of file diff --git a/tests/steam.ce b/tests/steam.ce deleted file mode 100644 index 31f35c7..0000000 --- a/tests/steam.ce +++ /dev/null @@ -1,117 +0,0 @@ -var steam = use('steam') - -log.console("STEAM!") - -// Test Steam functionality -if (steam && steam.user) { - var isLoggedOn = steam.user.logged_on() - log.console("Steam user logged on:", isLoggedOn) - if (isLoggedOn) { - var userName = steam.friends.name() - var steamId = steam.user.steam_id() - var appId = steam.app.id() - log.console("Steam user name: '" + userName + "'") - log.console("Steam user ID: '" + steamId.toString() + "'") - log.console("Steam app ID: " + appId.toString()) - - // Request user stats for achievements - steam.stats.request() - - // Display online friends - log.console("\n=== ONLINE FRIENDS ===") - var friendCount = steam.friends.count(1) // EFriendFlagImmediate = 1 - if (friendCount > 0) { - for (var i = 0; i < friendCount; i++) { - var friend = steam.friends.get_friend(i, 1) - if (friend) { - var friendName = steam.friends.get_friend_persona_name(friend) - var friendState = steam.friends.get_friend_persona_state(friend) - // Only show online friends (state > 0) - if (friendState > 0) { - var stateNames = ["Offline", "Online", "Busy", "Away", "Snooze", "Looking to Trade", "Looking to Play"] - var stateName = stateNames[friendState] || "Unknown" - log.console(" " + friendName + " - " + stateName) - - // Check if friend is playing a game - var gameInfo = steam.friends.get_friend_game_played(friend) - if (gameInfo && gameInfo.game_id) { - var gameName = steam.friends.get_friend_rich_presence(friend, "steam_display") - if (gameName) { - log.console(" Playing: " + gameName) - } else { - log.console(" Playing game ID: " + gameInfo.game_id) - } - } - } - } - } - } else { - log.console(" No friends found or friends list not loaded yet") - } - - // Display achievement information - log.console("\n=== ACHIEVEMENTS ===") - var achievementCount = steam.achievement.count() - if (achievementCount > 0) { - log.console("Total achievements: " + achievementCount) - - for (var i = 0; i < achievementCount; i++) { - var achName = steam.achievement.name(i) - if (achName) { - var achieved = steam.achievement.get(achName) - var displayName = steam.achievement.get_display_attribute(achName, "name") - var description = steam.achievement.get_display_attribute(achName, "desc") - - if (achieved) { - var unlockInfo = steam.achievement.get_and_unlock_time(achName) - if (unlockInfo) { - var unlockDate = new Date(unlockInfo.unlock_time * 1000) - log.console(" ✓ " + (displayName || achName) + " - Unlocked " + unlockDate.toLocaleDateString()) - } else { - log.console(" ✓ " + (displayName || achName) + " - Unlocked") - } - } else { - // Check for progress on this achievement - var progressInt = steam.achievement.get_progress_limits_int(achName) - var progressFloat = steam.achievement.get_progress_limits_float(achName) - - var progressText = "" - if (progressInt && progressInt.max_progress > 0) { - progressText = " (Progress: " + progressInt.min_progress + "/" + progressInt.max_progress + ")" - } else if (progressFloat && progressFloat.max_progress > 0) { - progressText = " (Progress: " + progressFloat.min_progress.toFixed(1) + "/" + progressFloat.max_progress.toFixed(1) + ")" - } - - log.console(" ✗ " + (displayName || achName) + progressText) - if (description) { - log.console(" " + description) - } - } - } - } - - // Show global achievement stats if available - steam.stats.request_global_achievement_percentages() - - // Get most achieved achievement info - var mostAchieved = steam.achievement.get_most_achieved_info() - if (mostAchieved) { - log.console("\nMost achieved: " + mostAchieved.name + " (" + mostAchieved.percent.toFixed(1) + "% of players)") - } - } else { - log.console("No achievements found for this game") - } - - // Display user phone/security status - log.console("\n=== ACCOUNT SECURITY ===") - log.console("Phone verified: " + steam.user.is_phone_verified()) - log.console("Two-factor enabled: " + steam.user.is_two_factor_enabled()) - log.console("Behind NAT: " + steam.user.is_behind_nat()) - - // Display user level and badge info if available - var userLevel = steam.user.level() - if (userLevel > 0) { - log.console("Steam level: " + userLevel) - } - } -} \ No newline at end of file diff --git a/tests/steam.cm b/tests/steam.cm new file mode 100644 index 0000000..6c91128 --- /dev/null +++ b/tests/steam.cm @@ -0,0 +1,141 @@ +var steam = use('steam') +var time = use('time') + +return { + test_steam_login_status: function() { + var isLoggedOn = steam.user.logged_on() + log.console("Steam user logged on: " + isLoggedOn) + if (isLoggedOn) { + var userName = steam.friends.name() + var steamId = steam.user.steam_id() + var appId = steam.app.id() + log.console("Steam user name: '" + userName + "'") + log.console("Steam user ID: '" + steamId.toString() + "'") + log.console("Steam app ID: " + appId.toString()) + } + }, + + test_steam_stats_request: function() { + if (steam.user.logged_on()) { + // Request user stats for achievements + steam.stats.request() + } + }, + + test_steam_friends: function() { + if (!steam.user.logged_on()) return; + + // Display online friends + log.console("\n=== ONLINE FRIENDS ===") + var friendCount = steam.friends.count(1) // EFriendFlagImmediate = 1 + if (friendCount > 0) { + for (var i = 0; i < friendCount; i++) { + var friend = steam.friends.get_friend(i) + if (friend) { + var friendName = steam.friends.get_friend_persona_name(friend) + var friendState = steam.friends.get_friend_persona_state(friend) + // Only show online friends (state > 0) + if (friendState > 0) { + var stateNames = ["Offline", "Online", "Busy", "Away", "Snooze", "Looking to Trade", "Looking to Play"] + var stateName = stateNames[friendState] || "Unknown" + log.console(" " + friendName + " - " + stateName) + + // Check if friend is playing a game + var gameInfo = steam.friends.get_friend_game_played(friend) + if (gameInfo && gameInfo.game_id) { + var gameName = steam.friends.get_friend_rich_presence(friend, "steam_display") + if (gameName) { + log.console(" Playing: " + gameName) + } else { + log.console(" Playing game ID: " + gameInfo.game_id) + } + } + } + } + } + } else { + log.console(" No friends found or friends list not loaded yet") + } + }, + + test_steam_achievements: function() { + if (!steam.user.logged_on()) return; + + // Display achievement information + log.console("\n=== ACHIEVEMENTS ===") + var achievementCount = steam.achievement.count() + if (achievementCount > 0) { + log.console("Total achievements: " + text(achievementCount)) + + for (var i = 0; i < achievementCount; i++) { + var achName = steam.achievement.name(i) + if (achName) { + var achieved = steam.achievement.get(achName) + var displayName = steam.achievement.get_display_attribute(achName, "name") + var description = steam.achievement.get_display_attribute(achName, "desc") + + if (achieved) { + var unlockInfo = steam.achievement.get_and_unlock_time(achName) + if (unlockInfo) { + var unlockDate = time.text(unlockInfo.unlock_time * 1000) + log.console(" ✓ " + (displayName || achName) + " - Unlocked " + unlockDate) + } else { + log.console(" ✓ " + (displayName || achName) + " - Unlocked") + } + } else { + // Check for progress on this achievement + var progressInt = steam.achievement.get_progress_limits_int(achName) + var progressFloat = steam.achievement.get_progress_limits_float(achName) + + var progressText = "" + if (progressInt && progressInt.max_progress > 0) { + progressText = " (Progress: " + progressInt.min_progress + "/" + progressInt.max_progress + ")" + } else if (progressFloat && progressFloat.max_progress > 0) { + progressText = " (Progress: " + progressFloat.min_progress.toFixed(1) + "/" + progressFloat.max_progress.toFixed(1) + ")" + } + + log.console(" ✗ " + (displayName || achName) + progressText) + if (description) { + log.console(" " + description) + } + } + } + } + } else { + log.console("No achievements found for this game") + } + }, + + test_steam_global_stats: function() { + if (!steam.user.logged_on()) return; + + // Show global achievement stats if available + steam.stats.request_global_achievement_percentages() + + // Get most achieved achievement info + var mostAchieved = steam.achievement.get_most_achieved_info() + if (mostAchieved) { + log.console("\nMost achieved: " + mostAchieved.name + " (" + mostAchieved.percent.toFixed(1) + "% of players)") + } + }, + + test_steam_security: function() { + if (!steam.user.logged_on()) return; + + // Display user phone/security status + log.console("\n=== ACCOUNT SECURITY ===") + log.console(`Phone verified: ${steam.user.is_phone_verified()}`) + log.console(`Two-factor enabled: ${steam.user.is_two_factor_enabled()}`) + log.console(`Behind NAT: ${steam.user.is_behind_nat()}`) + }, + + test_steam_level: function() { + if (!steam.user.logged_on()) return; + + // Display user level and badge info if available + var userLevel = steam.user.level() + if (userLevel > 0) { + log.console(`Steam level: ${userLevel}`) + } + } +}