getFriendGamePlayed missing the return of FriendGameInfo_t through a reference tag https://godotengine.org/qa/3611/how-to-bind-a-c-method-with-pointer-argument
is an essential feature to get friend lobbies working in godot.
See this code snipped (converted from an example from the steamworks docs:
func get_friend_lobbies():
var cFriends : int = Steam.getFriendCount()
for i in range(cFriends):
var friendGameInfo
var steamIDFriend = Steam.getFriendByIndex(i, Steam.FLAG_IMMEDIATE)
if ( Steam.getFriendGamePlayed(steamIDFriend, FriendGameInfo) && Steam.FriendGameInfo.m_steamIDLobby.IsValid() )
{
#Steam.FriendGameInfo.m_steamIDLobby is a valid lobby, you can join it or use Steam.requestLobbyData() get its metadata
}
#from the steamworks docs:
#for ( int i = 0; i < cFriends; i++ )
#{
# FriendGameInfo_t friendGameInfo;
# CSteamID steamIDFriend = SteamFriends()->GetFriendByIndex( i, k_EFriendFlagImmediate );
# if ( SteamFriends()->GetFriendGamePlayed( steamIDFriend, &friendGameInfo ) && friendGameInfo.m_steamIDLobby.IsValid() )
# {
# // friendGameInfo.m_steamIDLobby is a valid lobby, you can join it or use RequestLobbyData() get its metadata
# }
#}
The "proper" solution would be to return all the values that the base function provides in this wrapper function, however making a new function that returns a list of lobby id's from your friends using the above c++ code is a simple workaround for this specific issue. That is not an ideal solution however so I am working on implementing passing a reference myself, but I am not knowledgeable about how modules work quite yet, and do not know if I custom data types are allowed to be sent back or if it needs to be a VectorPoolArray. If someone already knows how to pass things by reference and has a fix for this, that would be awesome, otherwise I will be attempting to put together a pull request for this once i can figure out how to pass values by reference from a godot module.
Not entirely sure if something like this works:
// Returns true if the friend is actually in game and fills in pFriendGameInfo with an extra details.
bool Steam::getFriendGamePlayed(uint64_t steamID, Ref<FriendGameInfo_t> &gameInfo){
if(SteamFriends() == NULL){
return false;
}
//FriendGameInfo_t gameInfo;
CSteamID userID = (uint64)steamID;
bool isFriend = SteamFriends()->GetFriendGamePlayed(userID, gameInfo);
return isFriend;
}
Yeah, I believe the getFriendGamePlayed is on the "To-Do" list of fixes currently. Right now it only returns a bool instead of the full data needed, as you mentioned.
For our purposes the function would only need the Steam ID then resulting data would fill in a dictionary. Maybe something like...
Dictionary Steam::getFriendGamePlayed(uint64_t steamID){
Dictionary friendGame;
if(SteamFriends() == NULL){
return friendGame;
}
FriendGameInfo gameInfo;
CSteamId userId = (uint64)steamID;
bool success= SteamFriends()->GetFriendGamePlayed(userID, &gameInfo);
// If successful
if(success){
friendGame['id'] = gameInfo.gameID;
friendGame['ip'] = gameInfo.gameIP;
friendGame['gamePort'] = gameInfo.gamePort;
friendGame['queryPort'] = gameInfo.queryPort;
friendGame['lobby'] = gameInfo.steamIDLobby;
}
return friendGame;
}
This is completely untested so I'll assume it gives some kind of error during compilation.
What you wrote actually works in a whole other manner and is another solution. Since the FriendGameInfo struct already exists, you just populate it by calling SteamFriends->GetFriendGamePlayed(). When the current bool version of the function returns true, like in your example code, then you just pull data from the struct. Probably less messy than what I typed up above!
I'll try to tinker with it more this weekend.
UPDATE: In fact, I may already work as is... I never bothered to check to see if the struct contained the called data or not.
yeah looks like the dictionary thing you posted would work with the struct already in there, or it could be wrapped in a ref to be returned something like this above the class Steam: public Object {
```cpp
// Friend info //////////////////////////
struct FriendGameInfo {
uint64_t gameID;
uint32 gameIP;
uint16 gamePort;
uint16 queryPort;
uint64_t steamIDLobby;
};
class FriendGameInfoRef: public Reference {
GDCLASS(FriendGameInfoRef, Reference);
public:
FriendGameInfo_t gameInfo;//_FORCE_INLINE_
};```
the godot docs on this are really quite... limited
https://docs.godotengine.org/en/3.1/development/cpp/object_class.html?highlight=Ref%3C
update: I got the reference code compiling but it causes this error when called 'drivers\unix\net_socket_posix.cpp:190 - Socket error: 10054'
rather odd.
Edit: Added a pull request with my code so far https://github.com/Gramps/GodotSteam/pull/75
Yeah, the Godot documentation has gotten better but is still pretty lacking in a lot of areas. Not sure if we need the reference or not but I'll find out when I tinker with it this weekend!
If the pull request causes a crash I may not merge it in until we get that fixed up. I'll copy the code from you pull request and see what I can do with it!
Yeah, the Godot documentation has gotten better but is still pretty lacking in a lot of areas. Not sure if we need the reference or not but I'll find out when I tinker with it this weekend!
If the pull request causes a crash I may not merge it in until we get that fixed up. I'll copy the code from you pull request and see what I can do with it!
Yeah don't merge it haha. I assume the socket error is from causing a crash in the "server" that has the steam code running in it. I think it is a pointer / memory management related error
Haha, will do... or not do! If necessary it could probably be modeled on how ticket data works, which also has a struct. Granted I have never used that function in any tests.
Haha, will do... or not do! If necessary it could probably be modeled on how ticket data works, which also has a struct. Granted I have never used that function in any tests.
interesting. i'll take a look at those while i'm at it.
Updated Pull Request. The new code runs stable but I can't test if it actually receives the data just yet.
As I mention in the pull request, I got the function to return as a dictionary based on the code I showed above. It requires less modification to the rest of the module. While I won't be using the pull request code I did add you as a contributor in the documentation!
To test the the function, you just need to give it a friend's Steam ID 64. In your implementation, I guess you'd just call FriendGameInfoRef but would still have to get each part of it individually. Not sure if Godot would auto-complete the required data as you typed or not.
As I mention in the pull request, I got the function to return as a dictionary based on the code I showed above. It requires less modification to the rest of the module. While I won't be using the pull request code I did add you as a contributor in the documentation!
To test the the function, you just need to give it a friend's Steam ID 64. In your implementation, I guess you'd just call
FriendGameInfoRefbut would still have to get each part of it individually. Not sure if Godot would auto-complete the required data as you typed or not.
ahh thanks. yeah with bindings added for the class it should auto complete the correct names. It would likely be better with raw variables in it initialized from the struct. The goal being to match the syntax of the steamworks docs as closely as possible. The dictionary method isn't too far off.
There are some things I rename from Steamworks to simplify them. Even a few other functions that kind of encapsulate matching Steamworks functions since this isn't a raw C++ addition but an integration. Though as close as possible is good.
implemented a more complete version of this building on top of your methods code which contains both methods and several helper functions
Hey there! Will comment in the pull request to condense.