Steam API for GLBasic -> achievements, leaderboards for Your game ;-)

Previous topic - Next topic

dreamerman

Current version: 09.03.2022

This is my attempt to use Steam API or rather some of its parts in GLbasic. Yeah, it isn't clean code, not bullet-proof, and have some issues, it's still under constant development to fit my needs. Most important thing is that, user stats and achievements are working, tested on live app, leaderboards are under testing.

Download consist of two files:
steam_sdk.gbas -> imports for proper Steam API functions from dll, only part of functions were tested.
stats_manager.gbas -> Stat Manager type/object, main thing simplify using Steam stuff in game, supports user stats (int, float), achievements, leaderboards/highscore, and some help functions.

Take note, that if You will run project from Steam version GLBasic editor it will inherit its app_id, so You want be able to test it properly, not sure if putting 'steam_appid.txt' into project exe path should fix that, but You may need to either grab STDOUT to file or use alternative editor/older version.
Also read this: https://partner.steamgames.com/doc/features/achievements


How to use.
First create userstats, achievements, leaderboards on steamworks app admin panel.
Setup in game code:

1. set some object/udt for stats manager
Code (glbasic) Select
GLOBAL mySteam AS stats_manager_object, i1%
mySteam.Init(1)


2. set all
userstats, achievements - max value for stats to unlock achievements
Code (glbasic) Select

mySteam.addAchievement("points_1000")
mySteam.addAchievement("points_3000")
mySteam.addAchievement("10games_played")
mySteam.addUserStat("games_played", 10, 0, 0, 2) // 2 because '10games_played' achievement has such index in our in-game array
mySteam.addAchievement("collect_100_elixirs")
mySteam.addUserStat("elixirs_collected", 100, 0, 1, 3) // this is rapidly changing userstat

leaderboards - info, names
Code (glbasic) Select
mySteam.addLeaderboard("new_levels")
mySteam.addLeaderboard("classic_levels")
// if you want to use avatars create sprite for storing them - should be large to contain hundreds small avatars
mySteam.setLeaderboarOptions(1, 1)
CREATESCREEN 10, 10, 1024, 1024
mySteam.setAvatarsBufferInfo(9, 10)


3. fetch leaderboards main handles - provided by Steam (stats for current user are called in Init() internally, and processed with first RunFrame())
Code (glbasic) Select
mySteam.leaderboardPrepare()

4. additional setup:
to receive info when leaderboard is ready add this function:
Code (glbasic) Select
FUNCTION StatManager_LeaderboardReady%: handle AS int64, tab_id%, top_or_near%
    LOCAL i1%, pid%, tnick$
   
IF (game_menu% = CONST_HIGHSCORES)
IF (tab_id% = 0 AND top_or_near% = 0)
FOR i1% = 0 TO mySteam.leaderboards[tab_id%].top_count% - 1
pid% = mySteam.leaderboards[tab_id%].top_entry[i1%].id_onlist%
tnick$ = mySteam.usersinfo_list[pid%].nickname$
STDOUT "score: " + i1% + ": " + mySteam.leaderboards[tab_id%].top_entry[i1%].score% + " - " + tnick$ + "\n"
// avatars are stored on sprite defined with setAvatarsBufferInfo(), rectangle position left-top: mySteam.usersinfo_list[pid%].image_pos.x%, mySteam.usersinfo_list[pid%].image_pos.y%, mySteam.settings.avatars_size_px%, mySteam.settings.avatars_size_px%
NEXT
ENDIF
ENDIF
ENDFUNCTION


additional functions that may be usefull:
Code (glbasic) Select
StatManager_LeaderboardScoreUploaded() // called when score was uploaded

FUNCTION GLB_READ_ARGS%: caller_type% // to get cmd line arguments from Steam - when app is launched from browser
    LOCAL game_mode% = -1
    IF (caller_type% > 0)       // new query parameter
        game_mode% = Steam_API_Apps_GetLaunchQueryParam$("gamemode")
    ENDIF
    IF (game_mode% > -1)
// navigate to that game mode
    ENDIF
ENDFUNCTION


Usage after succesfull initialization:
Stats/achievements are ready to use after few RunFrame() calls, leaderboards after fetching handles - may take few extra ms.

for rapidly incremented userstats - destroyed enemies, items picked, doors unlocked...
Code (glbasic) Select
mySteam.updateUserStat(1, "elixirs_collected", 1, 0) // thats it, if this stat will reach its max/unlock value, 'mySteam.storeUserStats(0)' will be called automatically and proper achievement popup will be shown

for other achievements - beat some score to unlock use this:
Code (glbasic) Select
IF (match_points% >= 1000 AND mySteam.achievements_list[0].unlocked% = 0) THEN mySteam.unlockAchievement(0, "points_1000", 0)
IF (match_points% >= 3000 AND mySteam.achievements_list[1].unlocked% = 0) THEN mySteam.unlockAchievement(1, "points_3000", 0)
mySteam.storeUserStats(0) // this will show Steam achievement popup


to refresh leaderboards, for example when user clicks to 'Highscore' button in menu:
Code (glbasic) Select
mySteam.leaderboardRefresh(-1) // can be called in some longer intervals to get current/updated highscore

upload new score with
Code (glbasic) Select
mySteam.uploadHighscore(leaderboard_id%, user_score%, "")


If you will have any questions or issues let me know.
Check my source code editor for GLBasic - link Update: 20.04.2020

spacefractal

first time was due the compiler glbasic was used was simply just...... too old... but howover yes you are right as archivements, mostly in Genius Greedy Mouse (which have bounch of internal once) should do have them.

The compilers is updated and should been quite easy to integrate the steam SDK directly into the source code im should do this a day.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

dreamerman

Yeah, I wasn't sure but I though that Genius Greedy Mouse had some kind of 'achievements'.. I know that game should defend itself by quality, but now even small games have achievements, and some users just skip games without them with filters or just thinking that game isn't finished or due other reasons.
That's really nice to hear that such integration (into GLB source code) should be now easier to implement. As ability to call Steam API in such simple way (at least those basic things like stats, achievements, maybe leaderboards) would be awesome and that could be another great feature to list on Steam product page.
Check my source code editor for GLBasic - link Update: 20.04.2020

MrPlow

Achievements would be great to have for Steam - is this planned soon for a future update?
Comp:
Speccy-48k, Speccy-128k, Amigas, PCs

bigsofty

Yup, access to the Steam API in general would be very handy.

Nice bit of inlining there BTW Dreamerman!
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

spacefractal

Quote from: dreamerman on 2019-Apr-03
Yeah, I wasn't sure but I though that Genius Greedy Mouse had some kind of 'achievements'.. I know that game should defend itself by quality, but now even small games have achievements, and some users just skip games without them with filters or just thinking that game isn't finished or due other reasons.
That's really nice to hear that such integration (into GLB source code) should be now easier to implement. As ability to call Steam API in such simple way (at least those basic things like stats, achievements, maybe leaderboards) would be awesome and that could be another great feature to list on Steam product page.

When im did that game for some years ago, the glbasic compilers used was too old, so not include 'achievements' into source code. So im skipped it, but the game was also releaseed when its was easier to use trading cards (which im today kindy as, due there is too much abuse). So no im diddent include the sdk at all, but its should been possible today since compilers for the steam version is updated. Im did do support cloud support as its did not require to use SDK at all.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

dreamerman

#6
Hello, so much time passed, and I'm curious if anyone played with Steam SDK during that time. Because of that I'm bumping this topic, but that's not only reason.
Lately I was checking whats changed with this, one thing updating GCC used by GLBasic helped with some stuff, another thing that I noticed is very important update in Steam SDK - one of previous problems was Callback system, now Valve allows to use 'manual dispatch API' that lets to omit callback's completely. Still there are other issues, so shorting a long story: GLB uses GCC compiler, Steam_api.dll (and internal steam_client.dll) is compiled with MSVC this may cause some problems. I really don't like such messing with C++, all those standards, conventions, pointers, eh..
So really narrowing it down, thanks to all above we can include Steam API headers in GLB projects like this:

Code (glbasic) Select

// some Steam SDK playing around

// put 'Steam_SDK\redistributable_bin\steam_api.lib' to '\public' and 'steam_api.dll' to project .app folder where exe is
// add those commands to project options
// cmp -I"your_Steam_SDK_path\public\steam"
// lnk -L"your_Steam_SDK_path\public" -lsteam_api

// put below stuff in separate file
// in main source file just call Steam_Test()

INLINE
// why not to add this
//#include "iostream" // this is causing some errors now, in previous Steam SDK it was needed?
#include "stdio.h"
#include "stdint.h"
#include "assert.h"

// trick to add VS style nullptr to older GCC versions
// Scott Meyers. More Effective C++ 1996
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
const                        // this is a const object...
class {
public:
  template<class T>          // convertible to any type
    operator T*() const      // of null non-member
    { return 0; }            // pointer...
  template<class C, class T> // or any type of null
    operator T C::*() const  // member pointer...
    { return 0; }
private:
  void operator&() const;    // whose address can't be taken
} nullptr = {};

// current SteamSDK uses 'static_assert' macros in some functions
// trick to add static_assert support on older C/C++ standards (as GLB core wont compile properly on C++11)
// Joseph Quinsey : https://stackoverflow.com/questions/54357949/static-assert-for-c90-on-gcc
#define TOKENPASTE(a, b) a ## b // "##" is the "Token Pasting Operator"
#define TOKENPASTE2(a,b) TOKENPASTE(a, b) // expand then paste
#define static_assert(x, msg) enum { TOKENPASTE2(ASSERT_line_,__LINE__) = 1 / (msg && (x)) }


// and here goes Steam stuff
#include "steam_api.h"
// yeap that's all, now you can use it ;-)


//CSteamID your_uid; // some dummy test
ENDINLINE



FUNCTION Steam_Test%:
LOCAL init_ok%, user_lvl%, app_id%, owner_uid%, your_uid%, friends_count%
LOCAL your_name$, some_name$, test_str$
INLINE
init_ok = SteamAPI_Init();
user_lvl = SteamUser()->GetPlayerSteamLevel();
your_name_Str = SteamFriends()->GetPersonaName();
app_id = SteamUtils()->GetAppID(); // this will give GLBasic appid, as app runs from it, using it from standalone exe will give proper ID
CSteamID steamID;
AccountID_t taccountid;
steamID = SteamApps()->GetAppOwner(); // get CSteamID struct
owner_uid = steamID.ConvertToUint64(); // this should be Your SteamID3 ?? but for some reason it isn't or maybe I'm missing something
//taccountid = steamID.GetAccountID(); // unsigned int
//owner_uid = int(taccountid); // this also doesn't give proper Steam ID

// problems starts here
steamID = SteamUser()->GetSteamID(); // sometime this causes Access Violation Exception :-((
//taccountid = steamID.GetAccountID();
//your_uid = taccountid;
your_uid = steamID.ConvertToUint64(); // this should give your proper SteamID3
// both owner_uid and your_uid should be same, yet they differs, maybe some binary Flags are added that's not mentioned in docs

// even more mess, this is copied from official doc
int nFriends = SteamFriends()->GetFriendCount( k_EFriendFlagImmediate );
if ( nFriends == -1) nFriends = 0;
friends_count = nFriends; // this works
for ( int i = 0; i < nFriends; ++i )
{
CSteamID friendSteamID;
//friendSteamID = SteamFriends()->GetFriendByIndex( i, k_EFriendFlagImmediate ); // this will cause Access Violation Exception
//some_name_Str = SteamFriends()->GetFriendPersonaName( friendSteamID );
}


// end using Steam API
SteamAPI_Shutdown();
ENDINLINE
DEBUG "proper init: " + init_ok% + ", your lvl: " + (user_lvl%) + ", you name: '" + (your_name$) + "'"
DEBUG ", You have: " + (friends_count%) + " friends on Steam, some name: '" + some_name$ + "', your_id: " + your_uid%
DEBUG ", app_id: " + app_id% + ", owner_id: " + owner_uid% + "\n"
// if that debug was in one line then some variables get mesed up - like user_lvl%

ENDFUNCTION


Remember to put steam_api.lib & .dll to proper directories, above code is another concept how it could look when current issues would be resolved.
Using some stuff causes 'Access Violation Exceptions', some other things doesn't work properly from what I see and I'm not sure why, I'm just C++ peasant ;-)
With this method one important thing matters, You need to use Steam GLB version (>16) as it has newer GCC compiler. Probably some tricks could help with above mentioned problems, but it's just nah.. for me :/

Method showed in my first post - using Steam API functions through 'DECLARE' is still a solution, it's working with older GLB versions, it has some other issues but if achievements stuff would work it would be fine for me..


EDIT: my initial post - just to keep it in history:

I'm curious if anyone tried to make use of Steam API, for achievements, leaderboards or whatever.
As during fast looking at GLBasic made games on Steam I didn't see any project that support those features. Most notable would be support for achievements.

Some basic stuff can be done with INLINE, using DECLARE to call steam_api.dll functions.
main.gbas
Code (glbasic) Select
DEBUG "False: " + FALSE + ", True: " + TRUE + "\n"
DEBUG "Steam init: " + SAPI_SteamAPI_init() + "\n"
SAPI_SteamAPI_Shutdown()

steam_min.gbas
Code (glbasic) Select
INLINE
        }
                extern "C" {
                        #include <cstdio>
                       
                       
                }
        namespace __GLBASIC__ {
       
typedef bool _Bool;
typedef unsigned char uint8;
typedef signed char int8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;

const char* STEAMUSER_INTERFACE_VERSION = "SteamUser019";
       
typedef int32 HSteamPipe;
typedef int32 HSteamUser;
typedef int32 ISteamUser;


        DECLARE(SteamAPI_Init, "steam_api.dll", (), bool);
DECLARE(SteamAPI_Shutdown, "steam_api.dll", (), void);
DECLARE(SteamClient, "steam_api.dll", (), intptr_t);

        DECLARE(SteamAPI_ISteamClient_CreateSteamPipe, "steam_api.dll", (intptr_t), HSteamPipe);
        DECLARE(SteamAPI_ISteamClient_BReleaseSteamPipe, "steam_api.dll", (intptr_t, HSteamPipe), bool);
        DECLARE(SteamAPI_ISteamClient_ConnectToGlobalUser, "steam_api.dll", (intptr_t, HSteamPipe), HSteamUser);
DECLARE(SteamAPI_ISteamClient_GetISteamUser, "steam_api.dll", (intptr_t, HSteamUser, HSteamPipe, const char *), intptr_t);

DECLARE(SteamAPI_ISteamUser_GetPlayerSteamLevel, "steam_api.dll", (intptr_t), int);

ENDINLINE


FUNCTION SAPI_SteamAPI_init%:
LOCAL ret%, user_lvl%
INLINE
ret = SteamAPI_Init();
intptr_t sclient;
        sclient = SteamClient();
        HSteamPipe hsteampipe;
HSteamUser hsteamuser;
hsteampipe = SteamAPI_ISteamClient_CreateSteamPipe(sclient);
hsteamuser = SteamAPI_ISteamClient_ConnectToGlobalUser(sclient, hsteampipe);

intptr_t isteamuser;
isteamuser = SteamAPI_ISteamClient_GetISteamUser(sclient, hsteamuser, hsteampipe, STEAMUSER_INTERFACE_VERSION);;

user_lvl = SteamAPI_ISteamUser_GetPlayerSteamLevel(isteamuser);
SteamAPI_ISteamClient_BReleaseSteamPipe(sclient, hsteampipe);

ENDINLINE
DEBUG "your lvl: " + user_lvl% + "\n"
RETURN ret%
ENDFUNCTION

FUNCTION SAPI_SteamAPI_Shutdown%:
INLINE
SteamAPI_Shutdown();
ENDINLINE
ENDFUNCTION

Put 'steam_api.dll' to project exe folder, and create 'steam_appid.txt' containing your app_id to make this work. And result is that app will print in Debug Your (currently logged in) Steam Level (that from crafting game badges)..

Only issue with this, I have no idea how to make callback's from those functions (yet from what I saw, some other language ports just ignore this problem), many of them works asynchronously, and after completed they invoke/call some callback function, like this, you request for user stats, when Steam internal function get current stats, it callback to some function that normally is in project source. Can this be done with EXPORT, or are some other tricks to do this.
Including whole Steam API with 'steam_api_flat.h' header also can be some solution but proper including/linking is currently out of my scope :D Help of some C++ expert is needed here :P
Check my source code editor for GLBasic - link Update: 20.04.2020

dreamerman

In order to keep all things in one thread and keep it clean I will edit my first post with latest info, for archive reasons I've copied my initial post to my previous response.

And here is todays update.
As I'm getting closer with larger update to my Steam game, I was looking on few things that were hard to implement earlier, one of them were Steam Achievements.
Making it short, there are two ways to use Steam API: a) including it as C++ headers and using directly in inline or b) calling functions that are exported from dll.
a) may be more clean looking, yet it needs latest GLB version, and I still have some issues with either wrong calling convention, pointers or whatever.
b) could be more limited as probably not all functions can be used this way, but still it's a good solution.
After trying to get a) work I turned into option b) and.. Ehm it was supposed to be short ;-) Soo.. I made some help functions and here it is, an 'easy' way to add Steam Achievements to Your game.
Yeah, it isn't clean code, not bullet-proof, and have some issues and it's under constant development so it will fit my needs. Most important thing is that, user stats and achievements are working with it, tested on live app.

Take note, that if You will run project from Steam version GLBasic editor it will inherit its app_id, so You want be able to test it properly, not sure if putting 'steam_appid.txt' into project exe path should fix that, but You may need to either grab STDOUT to file or use alternative editor/older version.
Also read this: https://partner.steamgames.com/doc/features/achievements
Some example template to give Your an idea how to use it:

Code (glbasic) Select
GLOBAL mySteam AS stats_manager_object, i1%
mySteam.Init(1)      // after Init this will also request FOR current stats from Steam
i1% = mySteam.addAchievement("achiev_10_games_played")
mySteam.addUserStat("games_played", 10, 0, 0, i1%)
i1% = mySteam.addAchievement("achiev_10000_enemies_destroyed")
mySteam.addUserStat("enemies_destroyed", 10000, 0, 1, i1%)   // frequently changed value
// requestCurrentStats() was called internally in Init()
SETLOOPSUB "GLB_ON_LOOP" // set main loop FOR app
END   // exit app

// GLB_ON LOOPS
SUB GLB_ON_LOOP:
  mySteam.RunFrame()
   // after game played
   IF (match_finished) THEN mySteam.updateUserStat(-1, "games_played", 1, 1)   // increment by 1
   // OR you can do it manually
   IF (enemy_destroyed)
     INC mySteam.userstat_list[1].value_curr_int%
   ENDIF
   // IF You changed value manually THEN update it once per second - when calculation FPS
   IF last_fps_time - GETTIMERALL() >= 1000
     mySteam.updateUserStat(1, "", 0, 0) // update destroyed enemy counter
     // call only IF an achievement was unlocked - TO show it
     IF mySteam.status.achievement_was_unlocked% = 1 THEN mySteam.storeUserStats(0)
   ENDIF 
  IF KEY(01) THEN END // IF escape KEY THEN END app
ENDSUB
called on pausing AND before app exit
SUB GLB_ON_PAUSE:
// you need TO have them both AS RunFrame will call them when user open overlay
ENDSUB
// called on restoring app
SUB GLB_ON_RESUME:
ENDSUB
// called before app axit
SUB GLB_ON_QUIT:
  mySteam.Shoutdown()
ENDSUB



ps. download link in first post.
ps2. I rushed this a little just to post it today.
Check my source code editor for GLBasic - link Update: 20.04.2020

spacefractal

I'd want me to clean up posts let me know.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

MrPlow

Comp:
Speccy-48k, Speccy-128k, Amigas, PCs

dreamerman

@spacefractal
Thanks, but there is no need for deleting previous posts, I like to have all of them for tracking and archive reasons ;-)

@MrPlow
Generally whole Steam API can be used, yet this project will be rather limited to stats/achievements part and some basic utility functions that are needed to have those features. Currently I'm not even bothering with 'Avarage' type of UserStats, next thing to implement would be leaderboards, and this also doesn't seem to be difficult. Core stuff like RunFrame() functions can be used to add other features if someone needs, both Callback's and CallResult's responses seems to work properly so there should be no problem. I will try to keep Stats_manager type/object simple and fairly clean.

Currently using dll's exported function through Declare seems more reliable to me, so for now I will stick to it. Possible test with native C++ interfaces may be done in future, yet as this solution is sufficient for me (at least for know) I have no need to push on that. If someone needs, additional functions can be easily added, for example to launch web-browser in Steam overlay just this:
Code (glbasic) Select
Steam_API_SteamFriends_ActivateGameOverlayToWebPage("https://www.glbasic.com/forum/index.php")
Check my source code editor for GLBasic - link Update: 20.04.2020

spacefractal

you can dw the source code for real implematin, but this works well as we can only currectly uses for Windows anyway. O Its was to easier track like im also cleaned up. but im wont touch any posts, except if you pm me.

Im should finally looks with archivements for Greedy Mouse as that game internally allready have them.....
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

SnooPI

It's very interesting Dreamerman.
One day I will have to take a closer look.

dreamerman

I'm using this dll method from more than year in my game for user stats/achievements and they are working without issues (at least didn't notice any and no user complained about that) so I think that's good enough for a workaround method :]
This update comes with many added functions and handlers for Steam API callbacks, but only those that most likely will be used in any GLB made game. Some changes in core functions, but most important is leader boards support added, partially tested, due to how it works, I will verify everything after adding Steam Leaderboards/Highscore system in my next project.

Module updated to use latest 1.52 API interfaces, generally most changes in Steam API were made to add support for Steam Deck. About that thing, controller support in GLB is good out of box (even get controller names), vibration can be added with SDL inline so I don't see reason to bother with Steam_Input interface for now, specially that I don't have any gamepad/controller at moment :/
Check my source code editor for GLBasic - link Update: 20.04.2020

dreamerman

Updated to latest Steamworks 1.53a.
Support for Steam Leaderboards added, partially tested, I would need to have much more entries on high scores with different players, but didn't encounter issues for moment on limited leaderboards. Major thing is automated downloading user avatars and pasting them on GLB sprite-atlas (thanks to great FASTMEM2SPRITE by Qedo), that allows to use them directly in game with DrawAnim/PolyVector. Didn't test it in proper game yet, not sure about possible conflicts in inline declarations, but I will work on this soon.

As the way how everything works in Steamworks - is provided by Steam Client app and can be async retrieved during main loop, this is proper way to implement this feature in your game:
1. create leaderboards on steamworks app page,
2. in-game-code set leaderboards names, additional info - to download avatars
Code (glbasic) Select
mySteam.addLeaderboard("new_levels")
mySteam.addLeaderboard("classic_levels")
// if you want to use avatars create sprite for storing them - should be large to contain hundreds small avatars
mySteam.setLeaderboarOptions(1, 1)
CREATESCREEN 10, 10, 1024, 1024
mySteam.setAvatarsBufferInfo(9, 10)

3. fetch leaderboards main handles - provided by Steam
Code (glbasic) Select
mySteam.leaderboardPrepare()
4. refresh leaderboards - after loading initial game data, and successfully obtaining leaderboard handles
Code (glbasic) Select
mySteam.leaderboardRefresh(-1) // can be called in some longer intervals to get current highscore
5. when all info for entries of some leaderboard is downloaded (score is available right away, but nicks/avatars can be async) callback function is called, so you can update highscores info on screen
Code (glbasic) Select
FUNCTION StatManager_LeaderboardReady%: handle AS int64, tab_id%, top_or_near%
    LOCAL i1%, pid%, tnick$
       
    IF (top_or_near% = 0)
    FOR i1% = 0 TO mySteam.leaderboards[tab_id%].top_count% - 1
        pid% = mySteam.leaderboards[tab_id%].top_entry[i1%].id_onlist%
        tnick$ = mySteam.usersinfo_list[pid%].nickname$
        STDOUT "position: " + i1% + ", score: " + mySteam.leaderboards[tab_id%].top_entry[i1%].score% + " - " + tnick$ + "\n"
    NEXT
    ENDIF

ENDFUNCTION

6. upload new score with
Code (glbasic) Select
mySteam.uploadHighscore(leaderboard_id%, user_score%, "")

I'll add leaderboards to my published game to test it properly on larger scale, and will try to fix any possible encountered issues.
Achievements and leaderboards can be attracting factor is some cases (rare achievements hunters and so on), another thing that could be interesting is support for Steam Matchmaking to simplify or rather have compatible lobby/invite handling for games with multiplayer, but this is rather just for consideration, as I don't plan to work on this.
If you have suggestions for usefully Steam API functions to test let me know.
Check my source code editor for GLBasic - link Update: 20.04.2020