Search code examples
cluaffiluajitsteamworks-api

LuaJIT FFI: Uploading Steamworks leaderboards


How to use SteamAPICall_t with a SteamLeaderboard_t handle with LuaJIT FFI?
I use LÖVE2D framework & Steamworks Lua Integration (SLI)

Links: FindLeaderboard / UploadLeaderboardScore / Typedef

function UploadLeaderboards(score)
local char = ffi.new('const char*', 'Leaderboard name')
local leaderboardFound = steamworks.userstats.FindLeaderboard(char) -- Returns SteamAPICall_t
local leaderboardCurrent = ?? -- Use SteamAPICall_t with typedef SteamLeaderboard_t somehow.
local c = ffi.new("enum SteamWorks_ELeaderboardUploadScoreMethod", "k_ELeaderboardUploadScoreMethodKeepBest")
score = ffi.cast('int',math.round(score))
return steamworks.userstats.UploadLeaderboardScore(leaderboardCurrent, c, score, ffi.cast('int *', 0), 0ULL)
end


leaderboardCurrent = ffi.cast("SteamLeaderboard_t", leaderboardFound) -- No declaration error

Solution

  • SteamAPICall_t is simply a number that corresponds to your request. This is meant to be used alongside CCallback in the steam API. The lua integration misses out CCallback and STEAM_CALLBACK.

    The SteamLeaderboard_t response is generated by calling FindLeaderboard. In this case you are making a request to steam and steam needs to respond in an asynchronous way.

    So what you have to do is define a Listener object ( in C++ ) that will listen for the response ( which will be in form of SteamLeaderboard_t) and write C-like functions for it so ffi can understand them.

    This means that your program must be able to do this:

    1. Register a listener for the leaderboard.
    2. Submit a request for a leaderboard. ( FindLeaderboard )
    3. Wait for message ( SteamLeaderboard_t )
    4. Use SteamLeaderboard_t

    In short you will need to write code in C++ for the events and add C-like interface for them and compile it all into a DLL then link that DLL to lua using FFI. This can be tricky so exercise caution.

    in C (ffi.cdef and dll):

    //YOU have to write a DLL that defines these
    typedef struct LeaderboardEvents{
        void(*onLeaderboardFound)(SteamLeaderboard_t id);
    } LeaderboardEvents;
    void MySteamLib_attachListener(LeaderboardEvents* events);
    

    Then in lua.

    local lib = --load your DLL library here
    local Handler = ffi.new("LeaderboardEvents")
    
    Handler.onLeaderboardFound = function(id)
       -- do your stuff here.
    end
    
    lib.MySteamLib_attachListener(Handler)
    

    While writing your DLL, I STRONGLY recommend that you read through the SpaceWar example provided by steam api so you can see how callbacks are registered.