Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send additional data to Chobby to be independent from steam overlay #2433

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ChobbyLauncher/ChobbyLoopbackMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,20 @@ public class DownloadFileProgress
[ChobbyMessage]
public class SteamOnline
{

public string AuthToken { get; set; }
public List<string> Friends { get; set; }
public string FriendSteamID { get; set; }
public string SuggestedName { get; set; }
public List<ulong> Dlc { get; set; }
}

[ChobbyMessage]
public class SteamFriendList
{

public List<SteamFriend> Friends { get; set; }
}

[ChobbyMessage]
public class SteamOffline
{
Expand Down
2 changes: 1 addition & 1 deletion ChobbyLauncher/Chobbyla.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ private void ClearSdp()
public bool Run(ulong initialConnectLobbyID, TextWriter writer)
{
Status = "Connecting to steam API";
using (var steam = new SteamClientHelper())
using (var steam = new SteamClientHelper(this))
{
steam.ConnectToSteam();

Expand Down
17 changes: 15 additions & 2 deletions ChobbyLauncher/ChobbylaLocalListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using PlasmaDownloader;
using PlasmaShared;
using ZkData;
using static ChobbyLauncher.SteamOnline;
using Timer = System.Threading.Timer;

namespace ChobbyLauncher
Expand Down Expand Up @@ -47,6 +48,7 @@ public ChobbylaLocalListener(Chobbyla chobbyla, SteamClientHelper steam, ulong i
steam.OverlayActivated += SteamOnOverlayActivated;
steam.SteamOnline += () => { SendSteamOnline(); };
steam.SteamOffline += () => { SendSteamOffline(); };
steam.FriendListUpdate += (freund) => { SendFriendList(); };
discordController = new DiscordController(GlobalConst.ZeroKDiscordID, GlobalConst.SteamAppID.ToString());
discordController.OnJoin += DiscordOnJoinCallback;
discordController.OnDisconnected += DiscordOnDisconnectedCallback;
Expand Down Expand Up @@ -722,6 +724,7 @@ private async Task OnConnected()
try
{
await SendSteamOnline();
await SendFriendList();

}
catch (Exception ex)
Expand Down Expand Up @@ -756,13 +759,12 @@ private async Task SendSteamOnline()
{
var friendId = initialConnectLobbyID != 0 ? steam.GetLobbyOwner(initialConnectLobbyID) : null;



await
SendCommand(new SteamOnline()
{
AuthToken = steam.AuthToken,
Friends = steam.Friends.Select(x => x.ToString()).ToList(),
FriendSteamID = friendId?.ToString(),
SuggestedName = steam.MySteamNameSanitized,
Dlc = steam.GetDlcList()
Expand All @@ -772,6 +774,17 @@ private async Task SendSteamOnline()
}
}

private async Task SendFriendList()
{
if (steam.IsOnline)
{
await SendCommand(new SteamFriendList()
{
Friends = steam.Friends.Values.ToList()
});
}
}

private async Task SendSteamOffline()
{
await SendCommand(new SteamOffline());
Expand Down
111 changes: 100 additions & 11 deletions ChobbyLauncher/SteamClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
using ZkData;
using System.Net.NetworkInformation;
using Timer = System.Timers.Timer;
using System.IO;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using Newtonsoft.Json;

namespace ChobbyLauncher
{
Expand All @@ -36,6 +41,7 @@ public enum OverlayOption

private bool isDisposed;

private Callback<PersonaStateChange_t> friendStateChangeCallback;
private Callback<GameLobbyJoinRequested_t> lobbyJoinRequestCallback;
private Callback<P2PSessionRequest_t> newConnectionCallback;
private Callback<GameOverlayActivated_t> overlayActivatedCallback;
Expand All @@ -47,14 +53,20 @@ public enum OverlayOption

public string AuthToken { get; private set; }

public List<ulong> Friends { get; private set; }
public ConcurrentDictionary<ulong, SteamFriend> Friends { get; private set; }
public bool IsOnline { get; private set; }
public ChobbylaLocalListener Listener { get; set; }

public ulong? LobbyID { get; set; }

public string MySteamNameSanitized { get; set; }

private Chobbyla chobbyla;

public SteamClientHelper(Chobbyla chobbyla)
{
this.chobbyla = chobbyla;
}

public void Dispose()
{
Expand Down Expand Up @@ -85,11 +97,11 @@ public void ConnectToSteam()
public ulong? GetLobbyOwner(ulong lobbyID)
{
if (IsOnline)
foreach (var f in GetFriends())
foreach (var f in GetFriendIDs())
{
FriendGameInfo_t gi;
SteamFriends.GetFriendGamePlayed(new CSteamID(f), out gi);
if (gi.m_steamIDLobby.m_SteamID == lobbyID) return f;
SteamFriends.GetFriendGamePlayed(f, out gi);
if (gi.m_steamIDLobby.m_SteamID == lobbyID) return f.m_SteamID;
}
return null;
}
Expand Down Expand Up @@ -118,6 +130,9 @@ public void InviteFriendToGame(ulong lobbyID, ulong friendID)
if (IsOnline) SteamMatchmaking.InviteUserToLobby(new CSteamID(lobbyID), new CSteamID(friendID));
}


public event Action<SteamFriend> FriendListUpdate = (freund) => { };

public event Action<ulong> JoinFriendRequest = (steamID) => { };

public void OpenOverlaySection(OverlayOption option)
Expand Down Expand Up @@ -155,7 +170,7 @@ public void PrepareToHostP2PGame(SteamHostGameRequest request)
ulong.TryParse(player.SteamID, out playerSteamID);

p2pProxies[playerSteamID] = null;
SendSteamMessage(playerSteamID, new SteamP2PRequestPrepareProxy() {Channel = steamChannelCounter++});
SendSteamMessage(playerSteamID, new SteamP2PRequestPrepareProxy() { Channel = steamChannelCounter++ });
}

// wait for response
Expand Down Expand Up @@ -191,7 +206,7 @@ public void PrepareToHostP2PGame(SteamHostGameRequest request)
ScriptPassword = player.ScriptPassword
});
}

// send command to start spring to self
Listener.SendCommand(new SteamHostGameSuccess() { HostPort = gameHostUdpPort });
});
Expand Down Expand Up @@ -241,13 +256,34 @@ private string GetClientAuthTokenHex()
}


private List<ulong> GetFriends()
private ConcurrentDictionary<ulong, SteamFriend> GetFriends()
{
if (IsOnline)
{
var dic = new ConcurrentDictionary<ulong, SteamFriend>(GetFriendIDs().ToDictionary(x => x.m_SteamID, x => new SteamFriend()
{
Name = SteamFriends.GetFriendPersonaName(x),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add avatar

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But avatar would have to be downloaded to an image file in the lobby?! Is it worth doing this for all your steam friends?

CSteamID = x
}));
dic.ForEach(freund =>
{
var state = SteamFriends.GetFriendPersonaState(freund.Value.CSteamID);
freund.Value.IsOnline = state.HasFlag(EPersonaState.k_EPersonaStateOnline);
FriendGameInfo_t game;
freund.Value.IsPlaying = SteamFriends.GetFriendGamePlayed(freund.Value.CSteamID, out game) && (game.m_gameID.AppID().m_AppId == GlobalConst.SteamAppID);
});
return dic;
}
return null;
}

private List<CSteamID> GetFriendIDs()
{
if (IsOnline)
{
var ret = new List<ulong>();
var ret = new List<CSteamID>();
var cnt = SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate);
for (var i = 0; i < cnt; i++) ret.Add(SteamFriends.GetFriendByIndex(i, EFriendFlags.k_EFriendFlagImmediate).m_SteamID);
for (var i = 0; i < cnt; i++) ret.Add(SteamFriends.GetFriendByIndex(i, EFriendFlags.k_EFriendFlagImmediate));
return ret;
}
return null;
Expand All @@ -265,16 +301,55 @@ private ulong GetSteamID()
return 0;
}

private void DownloadAvatars(ICollection<CSteamID> users)
{
using (var wc = new WebClient())
{
var targetDir = Path.Combine(chobbyla.paths.WritableDirectory, "LuaUI", "Configs", "SteamAvatars");
if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir);
foreach (var user in users)
{
//download image via steamfriends
int handle = SteamFriends.GetMediumFriendAvatar(user);
uint imgW, imgH;
SteamUtils.GetImageSize(handle, out imgW, out imgH);
byte[] imgBuffer = new byte[4 * imgW * imgH];
GCHandle pinnedArray = GCHandle.Alloc(imgBuffer, GCHandleType.Pinned); //please make a better implementation of this
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
SteamUtils.GetImageRGBA(handle, imgBuffer, imgBuffer.Length);
var bitmap = new Bitmap((int)imgW, (int)imgH, 4 * (int)imgW, PixelFormat.Format32bppArgb, pointer);

var path = Path.Combine(targetDir, string.Format("{0}.png", user.m_SteamID));
if (File.Exists(path)) File.Delete(path);
bitmap.Save(path, ImageFormat.Png);

pinnedArray.Free();
}
}
}

private void OnFriendStateUpdate(PersonaStateChange_t u)
{
if (!Friends.ContainsKey(u.m_ulSteamID)) return; //Needed because this method is called for the player himself (not part of friend list)
var freund = Friends[u.m_ulSteamID];
if (u.m_nChangeFlags.HasFlag(EPersonaChange.k_EPersonaChangeComeOnline)) freund.IsOnline = true;
if (u.m_nChangeFlags.HasFlag(EPersonaChange.k_EPersonaChangeGoneOffline)) freund.IsOnline = false;
FriendGameInfo_t game;
freund.IsPlaying = SteamFriends.GetFriendGamePlayed(new CSteamID(u.m_ulSteamID), out game) && (game.m_gameID.AppID().m_AppId == GlobalConst.SteamAppID);
FriendListUpdate?.Invoke(freund);
}

private void OnSteamOnline()
{
Trace.TraceInformation("Steam online");

lobbyJoinRequestCallback = new Callback<GameLobbyJoinRequested_t>(t => { JoinFriendRequest(t.m_steamIDFriend.m_SteamID); });
overlayActivatedCallback = new Callback<GameOverlayActivated_t>(t => { OverlayActivated(t.m_bActive != 0); });
newConnectionCallback = Callback<P2PSessionRequest_t>.Create(t => SteamNetworking.AcceptP2PSessionWithUser(t.m_steamIDRemote));
friendStateChangeCallback = new Callback<PersonaStateChange_t>(t => OnFriendStateUpdate(t));
MySteamNameSanitized = Utils.StripInvalidLobbyNameChars(GetMyName());


var ev = new EventWaitHandle(false, EventResetMode.ManualReset);
AuthToken = GetClientAuthTokenHex();
CreateLobbyAsync((lobbyID) =>
Expand All @@ -284,8 +359,10 @@ private void OnSteamOnline()
});
SteamNetworking.AllowP2PPacketRelay(true);
Friends = GetFriends();
Task.Factory.StartNew(() => DownloadAvatars(Friends.Values.Select(x => x.CSteamID).ToList()));
ev.WaitOne(2000);
SteamOnline?.Invoke();
FriendListUpdate?.Invoke(null);
}

private void ProcessMessage(ulong remoteUser, Dummy cmd)
Expand Down Expand Up @@ -323,7 +400,7 @@ private void DisposeExistingProxies()
/// </summary>
private void ProcessMessage(ulong remoteUser, SteamP2PConfirmCreateProxy cmd)
{
p2pProxies[remoteUser] = new SteamP2PPortProxy(cmd.Channel, new CSteamID(remoteUser), gameHostUdpPort);
p2pProxies[remoteUser] = new SteamP2PPortProxy(cmd.Channel, new CSteamID(remoteUser), gameHostUdpPort);
}

/// <summary>
Expand Down Expand Up @@ -425,4 +502,16 @@ private void TimerOnElapsed(object sender)
}
}
}

public class SteamFriend
{
private CSteamID _cSteamID;

[JsonIgnore]
public CSteamID CSteamID { get { return _cSteamID; } set { _cSteamID = value; SteamID = value.m_SteamID; } }
public ulong SteamID { get; private set; }
public string Name;
public bool IsOnline;
public bool IsPlaying; //whether friend is playing zk right now
}
}