Beta Release
This commit is contained in:
+227
@@ -0,0 +1,227 @@
|
||||
using System;
|
||||
using MSCLoader;
|
||||
using Steamworks;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam-Lobby für P2P: Host erstellt eine Freunde-Lobby, lädt über das Steam-Overlay ein,
|
||||
/// Freunde treten über die Einladung bzw. "Spiel beitreten" bei. Die eigentlichen Daten
|
||||
/// laufen danach über Steam P2P (siehe SteamConnection).
|
||||
/// </summary>
|
||||
public class SteamLobby
|
||||
{
|
||||
const string VersionKey = "msco_version";
|
||||
const uint ChatMemberLeftMask = 2 | 4 | 8 | 16; // Left, Disconnected, Kicked, Banned
|
||||
|
||||
public CSteamID LobbyId { get; private set; }
|
||||
public bool InLobby { get { return LobbyId.m_SteamID != 0; } }
|
||||
|
||||
/// <summary>Lobby erstellt (Host).</summary>
|
||||
public event Action<CSteamID> Created;
|
||||
/// <summary>Lobby betreten (Client): Lobby-ID und Host.</summary>
|
||||
public event Action<CSteamID, CSteamID> Entered;
|
||||
/// <summary>Einladung angenommen / "Spiel beitreten" im Freundesfenster.</summary>
|
||||
public event Action<CSteamID> JoinRequested;
|
||||
/// <summary>Jemand hat die Lobby verlassen (Steam-ID).</summary>
|
||||
public event Action<CSteamID> MemberLeft;
|
||||
/// <summary>Fehler (Text für die Statuszeile).</summary>
|
||||
public event Action<string> Failed;
|
||||
|
||||
CallResult<LobbyCreated_t> createdResult;
|
||||
CallResult<LobbyEnter_t> enterResult;
|
||||
Callback<GameLobbyJoinRequested_t> joinRequestedCallback;
|
||||
Callback<LobbyChatUpdate_t> chatUpdateCallback;
|
||||
Callback<P2PSessionRequest_t> sessionRequestCallback;
|
||||
bool initialized;
|
||||
|
||||
public static bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
try { return SteamAPI.IsSteamRunning() && SteamUser.GetSteamID().m_SteamID != 0; }
|
||||
catch { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
public static string PersonaName
|
||||
{
|
||||
get
|
||||
{
|
||||
try { return SteamFriends.GetPersonaName(); }
|
||||
catch { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
public static ulong OwnSteamId
|
||||
{
|
||||
get
|
||||
{
|
||||
try { return SteamUser.GetSteamID().m_SteamID; }
|
||||
catch { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
static HAuthTicket authTicket;
|
||||
static bool hasAuthTicket;
|
||||
|
||||
/// <summary>Steam-Anmeldeticket für dedizierte Server (der Server kann es bei Steam prüfen).</summary>
|
||||
public static byte[] CreateAuthTicket()
|
||||
{
|
||||
try
|
||||
{
|
||||
CancelAuthTicket();
|
||||
var buffer = new byte[1024];
|
||||
uint length;
|
||||
authTicket = SteamUser.GetAuthSessionTicket(buffer, buffer.Length, out length);
|
||||
hasAuthTicket = true;
|
||||
var ticket = new byte[length];
|
||||
Array.Copy(buffer, ticket, length);
|
||||
return ticket;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static void CancelAuthTicket()
|
||||
{
|
||||
if (!hasAuthTicket) return;
|
||||
hasAuthTicket = false;
|
||||
try { SteamUser.CancelAuthTicket(authTicket); } catch { }
|
||||
}
|
||||
|
||||
public bool Init()
|
||||
{
|
||||
if (initialized) return true;
|
||||
if (!IsAvailable) return false;
|
||||
try
|
||||
{
|
||||
createdResult = CallResult<LobbyCreated_t>.Create(OnLobbyCreated);
|
||||
enterResult = CallResult<LobbyEnter_t>.Create(OnLobbyEntered);
|
||||
joinRequestedCallback = Callback<GameLobbyJoinRequested_t>.Create(OnJoinRequested);
|
||||
chatUpdateCallback = Callback<LobbyChatUpdate_t>.Create(OnChatUpdate);
|
||||
sessionRequestCallback = Callback<P2PSessionRequest_t>.Create(OnSessionRequest);
|
||||
initialized = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ModConsole.Error("[MSCO] Steam init failed: " + e.Message);
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/// <summary>Jedes Frame aufrufen, damit Steam-Callbacks ankommen.</summary>
|
||||
public void Tick()
|
||||
{
|
||||
if (!initialized) return;
|
||||
try { SteamAPI.RunCallbacks(); } catch { }
|
||||
}
|
||||
|
||||
public void Create(int maxPlayers)
|
||||
{
|
||||
if (!Init()) { Fail("Steam is not running"); return; }
|
||||
Leave();
|
||||
createdResult.Set(SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, maxPlayers));
|
||||
}
|
||||
|
||||
public void Join(CSteamID lobby)
|
||||
{
|
||||
if (!Init()) { Fail("Steam is not running"); return; }
|
||||
Leave();
|
||||
enterResult.Set(SteamMatchmaking.JoinLobby(lobby));
|
||||
}
|
||||
|
||||
public void OpenInviteDialog()
|
||||
{
|
||||
if (InLobby) SteamFriends.ActivateGameOverlayInviteDialog(LobbyId);
|
||||
}
|
||||
|
||||
public void Leave()
|
||||
{
|
||||
if (!InLobby) return;
|
||||
try { SteamMatchmaking.LeaveLobby(LobbyId); } catch { }
|
||||
LobbyId = new CSteamID(0);
|
||||
}
|
||||
|
||||
public bool IsMember(CSteamID user)
|
||||
{
|
||||
if (!InLobby) return false;
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(LobbyId);
|
||||
for (int i = 0; i < count; i++)
|
||||
if (SteamMatchmaking.GetLobbyMemberByIndex(LobbyId, i) == user) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Callbacks
|
||||
|
||||
void OnLobbyCreated(LobbyCreated_t result, bool ioFailure)
|
||||
{
|
||||
if (ioFailure || result.m_eResult != EResult.k_EResultOK)
|
||||
{
|
||||
Fail("Could not create Steam lobby (" + result.m_eResult + ")");
|
||||
return;
|
||||
}
|
||||
LobbyId = new CSteamID(result.m_ulSteamIDLobby);
|
||||
SteamMatchmaking.SetLobbyData(LobbyId, VersionKey, MSCO.ModVersion);
|
||||
if (Created != null) Created(LobbyId);
|
||||
}
|
||||
|
||||
void OnLobbyEntered(LobbyEnter_t result, bool ioFailure)
|
||||
{
|
||||
if (ioFailure || result.m_EChatRoomEnterResponse != 1) // 1 = Success
|
||||
{
|
||||
Fail("Could not join the lobby (full or closed)");
|
||||
return;
|
||||
}
|
||||
LobbyId = new CSteamID(result.m_ulSteamIDLobby);
|
||||
|
||||
string hostVersion = SteamMatchmaking.GetLobbyData(LobbyId, VersionKey);
|
||||
if (!string.IsNullOrEmpty(hostVersion) && hostVersion != MSCO.ModVersion)
|
||||
{
|
||||
Leave();
|
||||
Fail("Version mismatch (host " + hostVersion + ", you " + MSCO.ModVersion + ")");
|
||||
return;
|
||||
}
|
||||
CSteamID owner = SteamMatchmaking.GetLobbyOwner(LobbyId);
|
||||
if (Entered != null) Entered(LobbyId, owner);
|
||||
}
|
||||
|
||||
void OnJoinRequested(GameLobbyJoinRequested_t request)
|
||||
{
|
||||
if (JoinRequested != null) JoinRequested(request.m_steamIDLobby);
|
||||
}
|
||||
|
||||
void OnChatUpdate(LobbyChatUpdate_t update)
|
||||
{
|
||||
if (update.m_ulSteamIDLobby != LobbyId.m_SteamID) return;
|
||||
if ((update.m_rgfChatMemberStateChange & ChatMemberLeftMask) == 0) return;
|
||||
if (MemberLeft != null) MemberLeft(new CSteamID(update.m_ulSteamIDUserChanged));
|
||||
}
|
||||
|
||||
void OnSessionRequest(P2PSessionRequest_t request)
|
||||
{
|
||||
// Nur Verbindungen von Spielern aus unserer Lobby annehmen
|
||||
if (IsMember(request.m_steamIDRemote))
|
||||
SteamNetworking.AcceptP2PSessionWithUser(request.m_steamIDRemote);
|
||||
}
|
||||
|
||||
void Fail(string message)
|
||||
{
|
||||
if (Failed != null) Failed(message);
|
||||
}
|
||||
|
||||
/// <summary>Wurde das Spiel über eine Steam-Einladung gestartet? ("+connect_lobby <id>")</summary>
|
||||
public static CSteamID LobbyFromCommandLine()
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
for (int i = 0; i < args.Length - 1; i++)
|
||||
{
|
||||
ulong id;
|
||||
if (args[i] == "+connect_lobby" && ulong.TryParse(args[i + 1], out id)) return new CSteamID(id);
|
||||
}
|
||||
return new CSteamID(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user