房间密码和房间人数调整

This commit is contained in:
wuwenbo 2026-05-23 16:44:14 +08:00
parent 03c33d6371
commit 97ce9f9078
4 changed files with 217 additions and 16 deletions

View File

@ -44,10 +44,13 @@ namespace TH1_Logic.Net
public void KickMember(ulong memberId);
// 创建房间
public void CreateLobby(int maxMembers = 4,bool isPublic = true);
public void CreateLobby(int maxMembers = 4,bool isPublic = true, string password = "");
// 加入房间
public void JoinLobbyById(ulong lobbyId);
public void JoinLobbyById(ulong lobbyId, string password = "");
// 通过邀请加入房间
public void JoinLobbyByInvite(ulong lobbyId);
// 离开当前房间
public void LeaveLobby();
@ -67,6 +70,9 @@ namespace TH1_Logic.Net
// 获取最大成员数
public int GetMemberLimit();
// 设置最大成员数
public bool SetMemberLimit(int maxMembers);
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId);
@ -104,7 +110,12 @@ namespace TH1_Logic.Net
public class LobbyBase : ILobby
{
public void JoinLobbyById(ulong lobbyId)
public void JoinLobbyById(ulong lobbyId, string password = "")
{
}
public void JoinLobbyByInvite(ulong lobbyId)
{
}
@ -176,7 +187,7 @@ namespace TH1_Logic.Net
return null;
}
public void CreateLobby(int maxMembers = 4,bool isPublic = true)
public void CreateLobby(int maxMembers = 4,bool isPublic = true, string password = "")
{
}
@ -193,6 +204,11 @@ namespace TH1_Logic.Net
return 0;
}
public bool SetMemberLimit(int maxMembers)
{
return false;
}
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId)
{

View File

@ -81,6 +81,14 @@ namespace TH1_Logic.Steam
private int _suppressP2PSendFailureLobbyErrors;
private const float SteamSessionCheckInterval = 1f;
private const int SteamSessionFailThreshold = 2;
private const string LobbyHasPasswordKey = "HasPassword";
private const string LobbyPasswordKey = "Password";
private const string LobbyIsPublicKey = "IsPublic";
private string _pendingLobbyPassword = "";
private bool _pendingLobbyIsPublic = true;
private CSteamID _pendingJoinLobby = CSteamID.Nil;
private string _pendingJoinPassword = "";
private bool _pendingJoinCheckPassword = true;
private string RoomName;
// 房间列表
@ -124,6 +132,7 @@ namespace TH1_Logic.Steam
private Callback<SteamServersDisconnected_t> _cbSteamServersDisconnected;
private Callback<SteamServerConnectFailure_t> _cbSteamServerConnectFailure;
private Callback<SteamShutdown_t> _cbSteamShutdown;
private Callback<LobbyDataUpdate_t> _cbLobbyDataUpdate;
// 搜索公开房间
private Callback<LobbyMatchList_t> _cbLobbyMatchList;
@ -255,6 +264,7 @@ namespace TH1_Logic.Steam
_cbSteamServersDisconnected = Callback<SteamServersDisconnected_t>.Create(OnSteamServersDisconnectedCallback);
_cbSteamServerConnectFailure = Callback<SteamServerConnectFailure_t>.Create(OnSteamServerConnectFailureCallback);
_cbSteamShutdown = Callback<SteamShutdown_t>.Create(OnSteamShutdownCallback);
_cbLobbyDataUpdate = Callback<LobbyDataUpdate_t>.Create(OnLobbyDataUpdateCallback);
// 初始化P2P
SimpleP2P.Instance.Initialize();
@ -469,7 +479,7 @@ namespace TH1_Logic.Steam
}
// 建房
public void CreateLobby(int maxMembers = 4, bool isPublic = true)
public void CreateLobby(int maxMembers = 4, bool isPublic = true, string password = "")
{
if (CurrentState != LobbyState.None)
{
@ -477,13 +487,20 @@ namespace TH1_Logic.Steam
return;
}
_pendingLobbyPassword = password ?? "";
_pendingLobbyIsPublic = isPublic;
CurrentState = LobbyState.Creating;
LogSystem.LogInfo($"Creating public lobby with max members: {maxMembers}");
LogSystem.LogInfo($"Creating {(isPublic ? "public" : "friends-only")} lobby with max members: {maxMembers}, hasPassword: {!string.IsNullOrEmpty(_pendingLobbyPassword)}");
SteamMatchmaking.CreateLobby(isPublic?ELobbyType.k_ELobbyTypePublic:ELobbyType.k_ELobbyTypeFriendsOnly, maxMembers);
}
// 加入房间
public void JoinLobby(CSteamID lobbyId)
public void JoinLobby(CSteamID lobbyId, string password = "")
{
JoinLobbyInternal(lobbyId, password, true, true);
}
private void JoinLobbyInternal(CSteamID lobbyId, string password, bool requestLobbyDataIfMissing, bool checkPassword)
{
if (CurrentState != LobbyState.None)
{
@ -491,6 +508,25 @@ namespace TH1_Logic.Steam
//return;
}
if (requestLobbyDataIfMissing && ShouldRequestLobbyDataBeforeJoin(lobbyId))
{
_pendingJoinLobby = lobbyId;
_pendingJoinPassword = password ?? "";
_pendingJoinCheckPassword = checkPassword;
if (!SteamMatchmaking.RequestLobbyData(lobbyId))
{
ClearPendingJoinLobby();
LogSystem.LogError($"Failed to request lobby data before joining: {lobbyId}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyJoinFailed);
OnLobbyErrorEvent?.Invoke("Failed to request lobby data before joining");
}
return;
}
if (checkPassword && !ValidateLobbyPasswordForJoin(lobbyId, password)) return;
// TODO 这里会涉及到房间子类对于UI的调用对于房间的多态是不合理的暂不处理糊屎
var version = SteamMatchmaking.GetLobbyData(lobbyId, "Version");
if (!string.IsNullOrEmpty(version) && ConfigManager.Instance.VersionCfg.CurVersionInfo.Version != version)
@ -573,10 +609,16 @@ namespace TH1_Logic.Steam
}
// 通过房间ID直接加入无需好友关系
public void JoinLobbyById(ulong lobbyId)
public void JoinLobbyById(ulong lobbyId, string password = "")
{
var lobbyCSteamId = new CSteamID(lobbyId);
JoinLobby(lobbyCSteamId);
JoinLobby(lobbyCSteamId, password);
}
public void JoinLobbyByInvite(ulong lobbyId)
{
var lobbyCSteamId = new CSteamID(lobbyId);
JoinLobbyInternal(lobbyCSteamId, "", true, false);
}
// 获取当前房间ID用于分享
@ -595,7 +637,7 @@ namespace TH1_Logic.Steam
}
// 通过房间码加入
public void JoinByRoomCode(string code)
public void JoinByRoomCode(string code, string password = "")
{
ulong lobbyId = Base36Decode(code);
if (lobbyId == 0)
@ -604,7 +646,68 @@ namespace TH1_Logic.Steam
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyJoinFailed);
return;
}
JoinLobbyById(lobbyId);
JoinLobbyById(lobbyId, password);
}
private bool ValidateLobbyPasswordForJoin(CSteamID lobbyId, string password)
{
if (!LobbyIsPublic(lobbyId)) return true;
if (!LobbyHasPassword(lobbyId)) return true;
var expectedPassword = SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey);
if (!string.IsNullOrEmpty(expectedPassword) && (password ?? "") == expectedPassword) return true;
var errorMsg = string.IsNullOrEmpty(expectedPassword)
? "Lobby password data is missing"
: "Lobby password mismatch";
LogSystem.LogInfo(errorMsg);
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyJoinFailed);
OnLobbyErrorEvent?.Invoke(errorMsg);
return false;
}
private bool ShouldRequestLobbyDataBeforeJoin(CSteamID lobbyId)
{
if (!lobbyId.IsValid()) return false;
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, "Game"))) return false;
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, "Version"))) return false;
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey))) return false;
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey))) return false;
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey))) return false;
return true;
}
private void ClearPendingJoinLobby()
{
_pendingJoinLobby = CSteamID.Nil;
_pendingJoinPassword = "";
_pendingJoinCheckPassword = true;
}
private bool LobbyHasPassword(CSteamID lobbyId)
{
var hasPasswordData = SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey);
if (IsTrueLobbyData(hasPasswordData)) return true;
if (IsFalseLobbyData(hasPasswordData)) return false;
return !string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey));
}
private bool LobbyIsPublic(CSteamID lobbyId)
{
var isPublicData = SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey);
if (IsTrueLobbyData(isPublicData)) return true;
if (IsFalseLobbyData(isPublicData)) return false;
return true;
}
private static bool IsTrueLobbyData(string value)
{
return value == "1" || string.Equals(value, "true", StringComparison.OrdinalIgnoreCase);
}
private static bool IsFalseLobbyData(string value)
{
return value == "0" || string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
}
private string Base36Encode(ulong value)
@ -730,6 +833,7 @@ namespace TH1_Logic.Steam
Version = SteamMatchmaking.GetLobbyData(CurrentLobby, "Version"),
CurrentPlayers = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby),
MaxPlayers = SteamMatchmaking.GetLobbyMemberLimit(CurrentLobby),
HasPassword = LobbyHasPassword(CurrentLobby),
};
var data = new InviteMessage();
data.LobbyInfo = lobbyInfo;
@ -801,6 +905,7 @@ namespace TH1_Logic.Steam
CurrentPlayers = SteamMatchmaking.GetNumLobbyMembers(lobbyId),
MaxPlayers = SteamMatchmaking.GetLobbyMemberLimit(lobbyId),
GameState = int.Parse(SteamMatchmaking.GetLobbyData(lobbyId, "GameState")),
HasPassword = LobbyHasPassword(lobbyId),
});
}
@ -820,6 +925,7 @@ namespace TH1_Logic.Steam
lobbyInfo.CurrentPlayers = SteamMatchmaking.GetNumLobbyMembers(cSteamId);
lobbyInfo.MaxPlayers = SteamMatchmaking.GetLobbyMemberLimit(cSteamId);
lobbyInfo.GameState = int.Parse(SteamMatchmaking.GetLobbyData(cSteamId, "GameState"));
lobbyInfo.HasPassword = LobbyHasPassword(cSteamId);
}
}
@ -947,6 +1053,8 @@ namespace TH1_Logic.Steam
if (data.m_eResult != EResult.k_EResultOK)
{
CurrentState = LobbyState.None;
_pendingLobbyPassword = "";
_pendingLobbyIsPublic = true;
LogSystem.LogError($"Failed to create lobby: {data.m_eResult}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyCreateFailed);
return;
@ -965,6 +1073,11 @@ namespace TH1_Logic.Steam
SteamMatchmaking.SetLobbyData(CurrentLobby, "RoomName", SelfName + MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.OutsideMultiplayRoomNameSuffix));
SteamMatchmaking.SetLobbyData(CurrentLobby, "RoomCode", GenerateRoomCode());
SteamMatchmaking.SetLobbyData(CurrentLobby, "GameState", "0");
SteamMatchmaking.SetLobbyData(CurrentLobby, LobbyHasPasswordKey, string.IsNullOrEmpty(_pendingLobbyPassword) ? "false" : "true");
SteamMatchmaking.SetLobbyData(CurrentLobby, LobbyPasswordKey, _pendingLobbyPassword);
SteamMatchmaking.SetLobbyData(CurrentLobby, LobbyIsPublicKey, _pendingLobbyIsPublic ? "true" : "false");
_pendingLobbyPassword = "";
_pendingLobbyIsPublic = true;
// 设置Rich Presence
SteamFriends.SetRichPresence("status", "In Lobby");
@ -1000,6 +1113,26 @@ namespace TH1_Logic.Steam
HandleLocalSteamSessionLost("Steam shutdown callback");
}
private void OnLobbyDataUpdateCallback(LobbyDataUpdate_t data)
{
var lobbyId = new CSteamID(data.m_ulSteamIDLobby);
if (!_pendingJoinLobby.IsValid() || lobbyId != _pendingJoinLobby) return;
var password = _pendingJoinPassword;
var checkPassword = _pendingJoinCheckPassword;
ClearPendingJoinLobby();
if (data.m_bSuccess == 0)
{
LogSystem.LogError($"Failed to refresh lobby data before joining: {lobbyId}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyJoinFailed);
OnLobbyErrorEvent?.Invoke("Failed to refresh lobby data before joining");
return;
}
JoinLobbyInternal(lobbyId, password, false, checkPassword);
}
// 加入请求回调
private void OnLobbyJoinRequestedCallback(GameLobbyJoinRequested_t data)
{
@ -1014,7 +1147,7 @@ namespace TH1_Logic.Steam
return;
}
JoinLobby(data.m_steamIDLobby);
JoinLobbyInternal(data.m_steamIDLobby, "", true, false);
}
// 进入房间回调
@ -1173,6 +1306,9 @@ namespace TH1_Logic.Steam
_isHandlingSessionLoss = false;
_steamSessionFailCount = 0;
_refreshSteamStatus = 0f;
_pendingLobbyPassword = "";
_pendingLobbyIsPublic = true;
ClearPendingJoinLobby();
// 清除Rich Presence
SteamFriends.ClearRichPresence();
@ -1421,6 +1557,53 @@ namespace TH1_Logic.Steam
if (!CurrentLobby.IsValid()) return 0;
return SteamMatchmaking.GetLobbyMemberLimit(CurrentLobby);
}
// 设置最大成员数
public bool SetMemberLimit(int maxMembers)
{
if (!IsLobbyOwner())
{
LogSystem.LogError("Only lobby owner can change lobby member limit");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
return false;
}
if (!CurrentLobby.IsValid())
{
LogSystem.LogError("Not in a lobby");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
return false;
}
if (maxMembers <= 0)
{
LogSystem.LogError($"Invalid lobby member limit: {maxMembers}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
return false;
}
int memberCount = GetMemberCount();
if (maxMembers < memberCount)
{
LogSystem.LogError($"Cannot set lobby member limit below current member count: limit={maxMembers}, current={memberCount}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
return false;
}
bool success = SteamMatchmaking.SetLobbyMemberLimit(CurrentLobby, maxMembers);
if (success)
{
LogSystem.LogInfo($"Lobby member limit changed to: {maxMembers}");
EventManager.Publish(new UpdateUIOutsideMultiplayLobbyList());
}
else
{
LogSystem.LogError($"Failed to change lobby member limit to: {maxMembers}");
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
}
return success;
}
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId)
@ -1510,6 +1693,7 @@ namespace TH1_Logic.Steam
_cbSteamServersDisconnected?.Dispose();
_cbSteamServerConnectFailure?.Dispose();
_cbSteamShutdown?.Dispose();
_cbLobbyDataUpdate?.Dispose();
LogSystem.LogInfo("SteamLobbyManager cleaned up");
}
@ -1529,5 +1713,6 @@ namespace TH1_Logic.Steam
public int CurrentPlayers;
public int MaxPlayers;
public int GameState;
public bool HasPassword;
}
}

View File

@ -87,8 +87,8 @@ namespace TH1_UI.Controller.Outside
void _OnBtnCheckClick()
{
//Step #1 加入对方lobby
LobbyManager.Instance.Lobby?.JoinLobbyById(_lobbyId);
LobbyManager.Instance.Lobby?.JoinLobbyByInvite(_lobbyId);
Close();
}
}
}
}

View File

@ -95,9 +95,9 @@ namespace TH1_UI.Controller.Top
Main.Instance.GameLogic.ChangeState(GameState.Menu);
//Step #2 加入对方lobby
LobbyManager.Instance.Lobby?.JoinLobbyById(_lobbyId);
LobbyManager.Instance.Lobby?.JoinLobbyByInvite(_lobbyId);
//Step #3 关闭画面
Close();
}
}
}
}