Closed TheAnthonyNL closed 10 years ago
IIRC when you send a join-chat message, you should receive persona state callbacks with the Source ID set to the chat room's SteamID. This will tell you what users are in the chat room.
I took a quick look at node-steam, but I couldn't find this functionality in any of the handler .js files.
It's all in ChatEnterCallback data with chat name online members count and few messageObjects (looks like those are JSON data ) with members info (rank, clan permissions and steamid)
https://gist.github.com/6d656368/4b2d7c9ba7b13d40c5a7 Excuse me my bad C# ( some people say i should never ever write code :) )
@6d656368 It might make more sense if you knew the data you were working with.
MessageObjects are derivatives of Valve's KeyValue class. They're normally written and read as binary. Here's the code that Valve uses for reading these.
Maybe, but that's a pretty old code, wasn't really interested in details, just wanted to get it working asap.
Thanks for the answers guys, looking into it now.
Here i am again, i edited the steamkit2 repo from here but i get this error now:
"The type name 'JobCallback' does not exist in the type 'SteamKit2.SteamClient'"
so either i did something wrong or the repo is slightly outdated?
JobCallback<T>
was removed as part of a recent refactoring of the callback system. You can use Callback<T>
with job based callbacks now.
Allright thanks, so i assume the following error is caused by new refactoring too
Cannot implicitly convert type 'SteamKit2.ICallbackMsg' to 'SteamKit2.CallbackMsg'. An explicit conversion exists (are you missing a cast?)
That would be caused by the same refactoring. Check the updated Samples solution on how to handle callbacks now if you need a reference, but you should be able to recompile with just a handful of small changes.
@Netshroud i know how to handle callbacks but and i also was able to recompile the dll but just my project failed.
// handle a special JobCallback differently than the others if (msg.IsType< SteamClient.JobCallback < SteamUser.UpdateMachineAuthCallback >>()) { msg.Handle< SteamClient.JobCallback < SteamUser.UpdateMachineAuthCallback >>( jobCallback => OnUpdateMachineAuthCallback(jobCallback.Callback, jobCallback.JobID) ); }
code which gives error. If i check what options there are for SteamClient.
Got a workaround for it, makes my bot disconnect sometimes when loading but it works.
@TheAnthonyNL could you please post your workaround here? I have the exact same issue.
Will do later today ... but note it was build on older version of steamkit.
It's no problem, my fix was with IGenericCallback instead of Callback, this fixed a part of my code, but then I got another error with the JobCallback again
Snap ... lost the code to steamkit project but i have the dll if you want it?
anyway the way i used it in my steambot program:
TestUserHandler.cs
public override void OnChatEnter(SteamKit2.SteamFriends.ChatEnterCallback callback)
{
List<string> chatters = new List<string>();
foreach (SteamFriends.MsgObject chat in callback.Chatters)
{
if (!chat.Rank.Equals(EClanPermission.Nobody))
{
if (chat.ChatterID != Bot.SteamClient.SteamID)
{
chatters.Add(chat.ChatterID.ConvertToUInt64().ToString());
}
}
}
tools.FillChatMembersData(chatters);
Console.Write("Chatroom {0} joined owned by {1}." + Environment.NewLine, callback.ChatID, callback.ClanID);
}
Tools.cs
/// <summary>
/// Method to fill a list of all current chat members of a group chat.
/// </summary>
/// <param name="database"></param>
public void FillChatMembersData(List<string> database)
{
Globals.data_online_chatters.Clear();
foreach (string member in database)
{
// Console.Write(member + "\n\r");
Globals.data_online_chatters.Add(member);
}
}
download to dll if this is allowed ... https://dl.dropboxusercontent.com/u/13120823/ShareX/2015/05/steamkit-dll-koelen3-from-anthony.rar
Thats how i got it working ...
@koelen3 any progress?
Yeah, I fixed the error ;) I'm now running into another error where I try to add all Dota2 or TF2 items in a single trade where I get a nullexceptionerror. I'll post about that when I'm on my pc in like half an hour probably
@koelen3 allright, glad i was able to help you. Mind posting the new steamkit code somehow?
Use
void HandleSteamMessage(ICallbackMsg msg)
So ICallbackMsg here
then we use
msg.Handle<SteamUser.UpdateMachineAuthCallback>(
authCallback => OnUpdateMachineAuthCallback(authCallback)
);
and finally
private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
//Was CallbackMsg msg;
//Fix is ICallbackMsg
ICallbackMsg msg;
while (!backgroundWorker.CancellationPending)
{
try
{
//msg = SteamClient.WaitForCallback(true);
msg = SteamClient.WaitForCallback(true);
HandleSteamMessage(msg);
}
catch (WebException e)
{
log.Error("URI: " + (e.Response != null && e.Response.ResponseUri != null ? e.Response.ResponseUri.ToString() : "unknown") + " >> " + e.ToString());
System.Threading.Thread.Sleep(5000);//Steam is down, retry in 5 seconds.
}
catch (Exception e)
{
log.Error(e.ToString());
log.Warn("Restarting bot...");
}
}
}
This should work on the newest steamkit version
I more meant the part of the only groupchat members of a chatroom inside the steamkit as i edited too much which got changed in newest version (though you fixed it, so thats why i asked it :D)
Oh, I ain't even using groupchat for my bot :D It's just a storage bot with limited admins, sorry I can't help you with it I guess.
@koelen3 ah my bad then :) i supposed you were looking for that but thanks on the other fix :).
@VoiDeD any chance you could look into the dll and tell me what is difference between the current version cause i got lost somehow ...
@TheAnthonyNL I'm not sure what you're asking.
@VoiDeD
http://puu.sh/iaBDv.txt is my old steamkit.steamfriends class and when i compare it to the current version ( https://github.com/SteamRE/SteamKit/blob/master/SteamKit2/SteamKit2/Steam/Handlers/SteamFriends/SteamFriends.cs ) it's changed a lot.
It hasn't changed significantly beyond the callback restructure. https://github.com/SteamRE/SteamKit/commits/master/SteamKit2/SteamKit2/Steam/Handlers/SteamFriends/SteamFriends.cs (451f66c and 6b86fdb)
@Netshroud thank you, i will look into this today and report back later on.
Is there any chance that those permissions can be implemented anytime soon? https://github.com/SteamRE/SteamKit/blob/master/SteamKit2/SteamKit2/Steam/Handlers/SteamFriends/Callbacks.cs#L613
@6d656368 posted solution AFAIK.
I've been trying to find ANY possible way to get channel permission of given user and couldn't find any possible way right now. It's quite easy to get list of chat users, but getting their permissions seems like impossible for me now.
Any help?
Cheers.
@JustArchi want to make that public of getting list of chat users you use atm (assuming you used the latest steamkit version)? I will happily help you out on the permissions problem.
This is not yet perfect, but it does the thing.
I think I included all relevant parts.
Basically it works like this: steamNicknameToID()
creates new object of my custom callbackEvent
class, it sets unique key which consists of literal + requestedNickname
, adds it to the global List of ongoing callbacks, then fires joinChat()
and waits for event to complete. I receive usual data in OnPersonaState()
, and if one of the response matches my previously defined literal + requestedNickname
, then I put all the data in that callback, and notifies waiter (steamNicknameToID()
) that it's ready. Of course it's not perfect because we may have a situation when requested nickname is not on the channel, so I made auto-wakeup after 3 seconds in case nickname cannot be found.
It's not 100% reliable, but works pretty nicely until SteamKit implements some good solution.
Now my problem is that I can't receive clan ranks in OnPersonaState()
, I already tried specifying custom ERequests in requestFriendInfo()
, and nothing works - ClanRank is always 0.
This paste has been removed! :(. could you reupload it please. So i could look for an solution for you.
Uh, I don't have it anymore as I rewrote my whole logic into a Dictionary of SteamID and HashSet. Now I just put and take away user SteamIDs into proper HashSet linked to Chatroom on joined/left events.
This is much simpler and faster.
Mind sharing that solution ?
It's really easy.
// ClanID to Members mapping
private static readonly Dictionary<ulong, HashSet<ulong>> steamChatMembersDictionary = new Dictionary<ulong, HashSet<ulong>>();
private static readonly object steamChatMembersDictionaryLock = new object();
Two functions then:
private static void steamMemberEnteredChat(ulong chatID, ulong steamID) {
HashSet<ulong> chatters;
lock (steamChatMembersDictionaryLock) {
if (!steamChatMembersDictionary.TryGetValue(chatID, out chatters)) {
chatters = new HashSet<ulong>();
steamChatMembersDictionary.Add(chatID, chatters);
}
}
chatters.Add(steamID);
}
private static void steamMemberLeftChat(ulong chatID, ulong steamID) {
HashSet<ulong> chatters;
if (steamChatMembersDictionary.TryGetValue(chatID, out chatters)) {
chatters.Remove(steamID);
}
}
And callbacks:
private static void OnMemberInfo(SteamFriends.ChatMemberInfoCallback callback) {
if (callback != null) {
SteamID chatID = callback.ChatRoomID;
SteamFriends.ChatMemberInfoCallback.StateChangeDetails stateChangeInfo = callback.StateChangeInfo;
if (chatID != null && stateChangeInfo != null) {
SteamID chatterID = stateChangeInfo.ChatterActedOn;
if (chatterID != null) {
switch (stateChangeInfo.StateChange) {
case EChatMemberStateChange.Entered:
steamMemberEnteredChat(chatID, chatterID);
break;
case EChatMemberStateChange.Banned:
case EChatMemberStateChange.Disconnected:
case EChatMemberStateChange.Kicked:
case EChatMemberStateChange.Left:
steamMemberLeftChat(chatID, chatterID);
break;
}
}
}
}
}
If you want to do it properly, you also need to handle initial onPersonaState when joining chat with members already being in it:
private static void OnPersonaState(SteamFriends.PersonaStateCallback callback) {
if (callback != null) {
SteamID steamID = callback.FriendID;
SteamID sourceSteamID = callback.SourceSteamID;
if (sourceSteamID.IsChatAccount) {
steamMemberEnteredChat(sourceSteamID, steamID);
}
}
}
Good luck.
Possible TODOs:
Of course it's only one possible solution, quite memory-intensive as you hold a HashSet of SteamIDs (ulongs), but it works and is good in terms of quality.
@justarchi managed to get it more completed as you wrote some todo.
Yeah. but my new solution is now more complex, but also much better in terms of quality and error-prone.
I created it like this.
I have an abstract class Chat.cs
which is a core for handling all of that: http://pastebin.com/nmewRagt
Then you need to forward all expected actions marked as virtual void
where you steam client receives them: http://pastebin.com/sLcsGkwV
Notice that two above examples contain my own code that is not needed to make it work, basically you only need forwarding.
So basically it works like this:
Main entrypoint (steam client) receives callbacks from all chats and all actions.
OnChatEnter()
initiates the action, and creates new Chat
if the chat object with received ID doesn't exist yet (it's GroupChat
in my case, it inherits it's core from Chat
)
All other important chat-related callbacks are then forwarded to proper chat object, which can be then handled in proper way, such as adding/removing guy from our active users on chat collection.
Finally, it's nice to note that in case of logged off situation, all users on all chats are cleared (in OnLoggedOn()
), and bot rejoins all of them automatically, so we receive new list of users shortly after.
I think this solution is excellent, can be a bit complex to understand at first, but you have excellent structure of Chat
object with Users
in it, and it's very nicely handled through callback forwarding mechanism.
Hello everyone,
Is it possible to get a list of all online chatroom members from a groupchat?
I've been struggling with this for a day now, i saw that steam for node.js ( https://github.com/seishun/node-steam ) has this functionality but i can't re-create it in the C# steambot... so maybe you guys can help me out?