Merge branch 'main' of http://10.27.17.121:3000/kawagiri/TH1
# Conflicts: # Unity/Assets/Resources/BT/BT.asset # Unity/Assets/Resources/BT/DiplomacyStage2.asset
This commit is contained in:
commit
8ab284e5e3
@ -30,7 +30,7 @@ MonoBehaviour:
|
||||
_version: 3.33
|
||||
_category:
|
||||
_comments:
|
||||
_translation: {x: -244.58202, y: -54.64604}
|
||||
_zoomFactor: 1
|
||||
_translation: {x: -120, y: 106}
|
||||
_zoomFactor: 0.6445859
|
||||
_haltSerialization: 0
|
||||
_externalSerializationFile: {fileID: 0}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -17,6 +17,7 @@ using Logic.Timeline;
|
||||
using RuntimeData;
|
||||
using TH1_Core.Events;
|
||||
using TH1_Core.Managers;
|
||||
using TH1_Logic.Steam;
|
||||
using TH1Renderer;
|
||||
using TH1Resource;
|
||||
using UnityEngine;
|
||||
@ -36,6 +37,7 @@ namespace TH1_Logic.Core
|
||||
public float AnimationSpeed = 1f;
|
||||
public bool DebugMode = false;
|
||||
public bool DebugHideCenterMessage = false;
|
||||
public bool SteamTest = false;
|
||||
|
||||
[Header("Play Settings")]
|
||||
public int cityCount;
|
||||
@ -132,6 +134,22 @@ namespace TH1_Logic.Core
|
||||
|
||||
//step #7 更新成就的情况
|
||||
AchievementDataManager.Instance.ReCheckAchievementDataNotComplete();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (SteamTest)
|
||||
{
|
||||
var obj = this.transform.Find("SteamTest");
|
||||
if (!obj)
|
||||
{
|
||||
obj = new GameObject("SteamTest").transform;
|
||||
obj.parent = this.transform;
|
||||
}
|
||||
|
||||
var com = obj.GetComponent<SteamTestManager>();
|
||||
if (!com) com = obj.gameObject.AddComponent<SteamTestManager>();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -223,18 +241,13 @@ namespace TH1_Logic.Core
|
||||
AudioManager.Instance.Update();
|
||||
ConfigManager.Instance.Update();
|
||||
|
||||
|
||||
//如果正在游戏中,执行下方的这些update
|
||||
InputLogic?.Update();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public bool HasArchive()
|
||||
{
|
||||
return PlayerPrefs.GetInt("Archive", 0) == 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Steam/Editor.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Steam/Editor.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4cdcbaca1344a0399ccc65bd583b481
|
||||
timeCreated: 1756803391
|
||||
@ -0,0 +1,119 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using System.IO;
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam Build后处理器 - 自动复制steam_appid.txt到Build目录
|
||||
/// </summary>
|
||||
public class SteamBuildPostProcessor
|
||||
{
|
||||
[PostProcessBuild(1)]
|
||||
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
|
||||
{
|
||||
// 只处理Windows平台的Build
|
||||
if (target != BuildTarget.StandaloneWindows && target != BuildTarget.StandaloneWindows64)
|
||||
return;
|
||||
|
||||
string projectRoot = Directory.GetParent(Application.dataPath).FullName;
|
||||
string steamAppIdSource = Path.Combine(projectRoot, "steam_appid.txt");
|
||||
|
||||
// 检查源文件是否存在
|
||||
if (!File.Exists(steamAppIdSource))
|
||||
{
|
||||
Debug.LogWarning("[Steam] steam_appid.txt not found in project root. Steam功能可能无法正常工作。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 确定目标路径(与exe文件同级)
|
||||
string buildDirectory = Path.GetDirectoryName(pathToBuiltProject);
|
||||
string steamAppIdTarget = Path.Combine(buildDirectory, "steam_appid.txt");
|
||||
|
||||
try
|
||||
{
|
||||
// 复制文件
|
||||
File.Copy(steamAppIdSource, steamAppIdTarget, true);
|
||||
Debug.Log($"[Steam] steam_appid.txt 已复制到Build目录: {steamAppIdTarget}");
|
||||
|
||||
// 读取并显示App ID
|
||||
string appId = File.ReadAllText(steamAppIdSource).Trim();
|
||||
Debug.Log($"[Steam] Steam App ID: {appId}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Steam] 复制steam_appid.txt失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动复制steam_appid.txt到指定Build目录
|
||||
/// </summary>
|
||||
[MenuItem("Tools/Steam/Copy steam_appid.txt to Build Directory")]
|
||||
public static void CopySteamAppIdToBuild()
|
||||
{
|
||||
string buildPath = EditorUtility.OpenFolderPanel("选择Build目录", "", "");
|
||||
if (string.IsNullOrEmpty(buildPath))
|
||||
return;
|
||||
|
||||
string projectRoot = Directory.GetParent(Application.dataPath).FullName;
|
||||
string steamAppIdSource = Path.Combine(projectRoot, "steam_appid.txt");
|
||||
|
||||
if (!File.Exists(steamAppIdSource))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "项目根目录下未找到steam_appid.txt文件", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
string steamAppIdTarget = Path.Combine(buildPath, "steam_appid.txt");
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(steamAppIdSource, steamAppIdTarget, true);
|
||||
EditorUtility.DisplayDialog("成功", $"steam_appid.txt已复制到:\n{steamAppIdTarget}", "确定");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", $"复制失败:\n{e.Message}", "确定");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前steam_appid.txt配置
|
||||
/// </summary>
|
||||
[MenuItem("Tools/Steam/Validate steam_appid.txt")]
|
||||
public static void ValidateSteamAppId()
|
||||
{
|
||||
string projectRoot = Directory.GetParent(Application.dataPath).FullName;
|
||||
string steamAppIdPath = Path.Combine(projectRoot, "steam_appid.txt");
|
||||
|
||||
if (!File.Exists(steamAppIdPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("配置错误",
|
||||
"未找到steam_appid.txt文件!\n\n请在项目根目录创建此文件并添加Steam App ID。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
string content = File.ReadAllText(steamAppIdPath).Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
EditorUtility.DisplayDialog("配置错误",
|
||||
"steam_appid.txt文件为空!\n\n请添加有效的Steam App ID。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uint.TryParse(content, out uint appId))
|
||||
{
|
||||
EditorUtility.DisplayDialog("配置错误",
|
||||
$"steam_appid.txt内容无效: {content}\n\n请确保文件只包含数字形式的App ID。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
string appName = appId == 480 ? " (Spacewar - 测试应用)" : "";
|
||||
EditorUtility.DisplayDialog("配置正确",
|
||||
$"steam_appid.txt配置正确!\n\nApp ID: {appId}{appName}\n文件位置: {steamAppIdPath}", "确定");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6a6223ed8844724b62fecf689fa257c
|
||||
timeCreated: 1756803391
|
||||
291
Unity/Assets/Scripts/TH1_Logic/Steam/SimpleP2P.cs
Normal file
291
Unity/Assets/Scripts/TH1_Logic/Steam/SimpleP2P.cs
Normal file
@ -0,0 +1,291 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Logic.CrashSight;
|
||||
using Steamworks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
public class SimpleP2P
|
||||
{
|
||||
public static SimpleP2P Instance { get; } = new SimpleP2P();
|
||||
|
||||
// 连接映射表:SteamID -> 连接句柄
|
||||
private readonly Dictionary<CSteamID, HSteamNetConnection> _connections = new Dictionary<CSteamID, HSteamNetConnection>();
|
||||
|
||||
// 监听套接字
|
||||
private HSteamListenSocket _listenSocket = HSteamListenSocket.Invalid;
|
||||
|
||||
// 回调
|
||||
private Callback<SteamNetConnectionStatusChangedCallback_t> _cbConnectionStatusChanged;
|
||||
|
||||
// 事件委托
|
||||
public event System.Action<CSteamID> OnPeerConnectedEvent;
|
||||
public event System.Action<CSteamID> OnPeerDisconnectedEvent;
|
||||
public event System.Action<CSteamID, byte[]> OnMessageReceivedEvent;
|
||||
public event System.Action<string> OnConnectionErrorEvent;
|
||||
|
||||
// 初始化
|
||||
public void Initialize()
|
||||
{
|
||||
_cbConnectionStatusChanged = Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
|
||||
|
||||
// 创建监听套接字
|
||||
CreateListenSocket();
|
||||
}
|
||||
|
||||
// 创建监听套接字
|
||||
private void CreateListenSocket()
|
||||
{
|
||||
// 使用默认端口0,Steam会自动分配
|
||||
_listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(0, 0, null);
|
||||
if (_listenSocket == HSteamListenSocket.Invalid)
|
||||
{
|
||||
OnConnectionErrorEvent?.Invoke("Failed to create listen socket");
|
||||
return;
|
||||
}
|
||||
LogSystem.LogInfo($"P2P Listen socket created: {_listenSocket}");
|
||||
}
|
||||
|
||||
// 连接到指定玩家
|
||||
public bool ConnectToPeer(CSteamID steamID)
|
||||
{
|
||||
if (_connections.ContainsKey(steamID))
|
||||
{
|
||||
LogSystem.LogInfo($"Already connected to {steamID}");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 创建到目标玩家的连接
|
||||
var identity = new SteamNetworkingIdentity();
|
||||
identity.SetSteamID(steamID);
|
||||
|
||||
var connection = SteamNetworkingSockets.ConnectP2P(ref identity, 0, 0, null);
|
||||
if (connection == HSteamNetConnection.Invalid)
|
||||
{
|
||||
OnConnectionErrorEvent?.Invoke($"Failed to connect to {steamID}");
|
||||
return false;
|
||||
}
|
||||
|
||||
_connections[steamID] = connection;
|
||||
LogSystem.LogInfo($"Connecting to peer: {steamID}");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 断开与指定玩家的连接
|
||||
public void DisconnectFromPeer(CSteamID steamID)
|
||||
{
|
||||
if (!_connections.TryGetValue(steamID, out var connection))
|
||||
return;
|
||||
|
||||
SteamNetworkingSockets.CloseConnection(connection, 0, "Disconnected by user", false);
|
||||
_connections.Remove(steamID);
|
||||
LogSystem.LogInfo($"Disconnected from peer: {steamID}");
|
||||
}
|
||||
|
||||
// 断开所有连接
|
||||
public void DisconnectAll()
|
||||
{
|
||||
foreach (var kvp in _connections)
|
||||
{
|
||||
SteamNetworkingSockets.CloseConnection(kvp.Value, 0, "Disconnecting all", false);
|
||||
}
|
||||
_connections.Clear();
|
||||
LogSystem.LogInfo("Disconnected from all peers");
|
||||
}
|
||||
|
||||
// 连接状态变化回调
|
||||
private void OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t info)
|
||||
{
|
||||
var state = info.m_info.m_eState;
|
||||
|
||||
// 获取连接信息
|
||||
SteamNetworkingSockets.GetConnectionInfo(info.m_hConn, out var connectionInfo);
|
||||
var remote = connectionInfo.m_identityRemote.GetSteamID();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting:
|
||||
LogSystem.LogInfo($"Connecting to {remote}...");
|
||||
break;
|
||||
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_FindingRoute:
|
||||
LogSystem.LogInfo($"Finding route to {remote}...");
|
||||
break;
|
||||
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connected:
|
||||
LogSystem.LogInfo($"Connected to {remote}");
|
||||
if (!_connections.ContainsKey(remote))
|
||||
{
|
||||
_connections[remote] = info.m_hConn;
|
||||
}
|
||||
OnPeerConnectedEvent?.Invoke(remote);
|
||||
break;
|
||||
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ClosedByPeer:
|
||||
LogSystem.LogInfo($"Connection closed by peer: {remote}");
|
||||
HandleDisconnection(remote, info.m_hConn);
|
||||
break;
|
||||
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
|
||||
LogSystem.LogWarning($"Connection problem detected locally: {remote}");
|
||||
HandleDisconnection(remote, info.m_hConn);
|
||||
break;
|
||||
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_None:
|
||||
// 连接被拒绝或失败
|
||||
LogSystem.LogError($"Connection failed or rejected: {remote}");
|
||||
HandleDisconnection(remote, info.m_hConn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理断开连接
|
||||
private void HandleDisconnection(CSteamID steamID, HSteamNetConnection connection)
|
||||
{
|
||||
if (_connections.ContainsKey(steamID))
|
||||
{
|
||||
_connections.Remove(steamID);
|
||||
OnPeerDisconnectedEvent?.Invoke(steamID);
|
||||
}
|
||||
SteamNetworkingSockets.CloseConnection(connection, 0, "", false);
|
||||
}
|
||||
|
||||
// 发送消息到指定玩家
|
||||
public bool SendTo(CSteamID target, byte[] data, bool reliable = true)
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
LogSystem.LogWarning("Trying to send null or empty data");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_connections.TryGetValue(target, out var conn))
|
||||
{
|
||||
LogSystem.LogWarning($"No connection to {target}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 可靠传输=8,不可靠传输=0
|
||||
int flags = reliable ? 8 : 0;
|
||||
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal(data.Length);
|
||||
Marshal.Copy(data, 0, ptr, data.Length);
|
||||
|
||||
var result = SteamNetworkingSockets.SendMessageToConnection(conn, ptr, (uint)data.Length, flags, out _);
|
||||
if (result != EResult.k_EResultOK)
|
||||
{
|
||||
LogSystem.LogError($"Failed to send message to {target}: {result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogError($"Exception while sending message: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// 广播消息给所有连接的玩家
|
||||
public void Broadcast(byte[] data, bool reliable = true)
|
||||
{
|
||||
foreach (var steamID in _connections.Keys)
|
||||
{
|
||||
SendTo(steamID, data, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
// 轮询接收消息
|
||||
public void PollMessages()
|
||||
{
|
||||
// 为每个连接轮询消息
|
||||
foreach (var kvp in _connections)
|
||||
{
|
||||
var steamID = kvp.Key;
|
||||
var connection = kvp.Value;
|
||||
|
||||
PollMessagesForConnection(steamID, connection);
|
||||
}
|
||||
}
|
||||
|
||||
// 为特定连接轮询消息
|
||||
private void PollMessagesForConnection(CSteamID steamID, HSteamNetConnection connection)
|
||||
{
|
||||
IntPtr[] messages = new IntPtr[32]; // 一次最多处理32条消息
|
||||
|
||||
int messageCount = SteamNetworkingSockets.ReceiveMessagesOnConnection(connection, messages, 32);
|
||||
|
||||
for (int i = 0; i < messageCount; i++)
|
||||
{
|
||||
var messagePtr = messages[i];
|
||||
if (messagePtr == IntPtr.Zero) continue;
|
||||
|
||||
try
|
||||
{
|
||||
// 获取消息结构
|
||||
var message = Marshal.PtrToStructure<SteamNetworkingMessage_t>(messagePtr);
|
||||
|
||||
// 复制数据
|
||||
byte[] data = new byte[message.m_cbSize];
|
||||
Marshal.Copy(message.m_pData, data, 0, message.m_cbSize);
|
||||
|
||||
// 触发接收事件
|
||||
OnMessageReceivedEvent?.Invoke(steamID, data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogError($"Error processing message from {steamID}: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 释放消息
|
||||
SteamNetworkingMessage_t.Release(messagePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取连接状态
|
||||
public bool IsConnectedTo(CSteamID steamID)
|
||||
{
|
||||
return _connections.ContainsKey(steamID);
|
||||
}
|
||||
|
||||
// 获取所有连接的玩家
|
||||
public IEnumerable<CSteamID> GetConnectedPeers()
|
||||
{
|
||||
return _connections.Keys;
|
||||
}
|
||||
|
||||
// 获取连接数量
|
||||
public int GetConnectionCount()
|
||||
{
|
||||
return _connections.Count;
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
public void Cleanup()
|
||||
{
|
||||
DisconnectAll();
|
||||
|
||||
if (_listenSocket != HSteamListenSocket.Invalid)
|
||||
{
|
||||
SteamNetworkingSockets.CloseListenSocket(_listenSocket);
|
||||
_listenSocket = HSteamListenSocket.Invalid;
|
||||
}
|
||||
|
||||
_cbConnectionStatusChanged?.Dispose();
|
||||
_cbConnectionStatusChanged = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Steam/SimpleP2P.cs.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Steam/SimpleP2P.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6d704b4f9b049d69589fb5dae84c372
|
||||
timeCreated: 1756715947
|
||||
520
Unity/Assets/Scripts/TH1_Logic/Steam/SteamLobbyManager.cs
Normal file
520
Unity/Assets/Scripts/TH1_Logic/Steam/SteamLobbyManager.cs
Normal file
@ -0,0 +1,520 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Logic.CrashSight;
|
||||
using Steamworks;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
public class SteamLobbyManager
|
||||
{
|
||||
public static SteamLobbyManager Instance { get; } = new SteamLobbyManager();
|
||||
|
||||
public CSteamID CurrentLobby = CSteamID.Nil;
|
||||
public CSteamID CachedOwner = CSteamID.Nil;
|
||||
|
||||
// 房间状态
|
||||
public enum LobbyState
|
||||
{
|
||||
None, // 未在房间中
|
||||
Creating, // 正在创建房间
|
||||
Joining, // 正在加入房间
|
||||
InLobby, // 在房间中
|
||||
Leaving // 正在离开房间
|
||||
}
|
||||
|
||||
public LobbyState CurrentState { get; private set; } = LobbyState.None;
|
||||
|
||||
public bool IsLobbyOwner =>
|
||||
CurrentLobby.IsValid() &&
|
||||
SteamMatchmaking.GetLobbyOwner(CurrentLobby) == SteamUser.GetSteamID();
|
||||
|
||||
public bool IsInLobby => CurrentState == LobbyState.InLobby && CurrentLobby.IsValid();
|
||||
|
||||
// 事件委托
|
||||
public event System.Action<CSteamID> OnLobbyCreatedEvent; // 房间创建成功
|
||||
public event System.Action<CSteamID> OnLobbyEnteredEvent; // 进入房间
|
||||
public event System.Action OnLobbyLeftEvent; // 离开房间
|
||||
public event System.Action<CSteamID, CSteamID> OnHostChangedEvent; // 房主变更 (oldHost, newHost)
|
||||
public event System.Action<List<CSteamID>> OnMembersChangedEvent; // 成员变化
|
||||
public event System.Action<string> OnLobbyErrorEvent; // 房间错误
|
||||
public event System.Action<CSteamID> OnMemberJoinedEvent; // 成员加入
|
||||
public event System.Action<CSteamID> OnMemberLeftEvent; // 成员离开
|
||||
|
||||
// LobbyCreated_t
|
||||
// 谁会收到:只有调用 CreateLobby 的本机(创建者)。
|
||||
// 何时触发:SteamMatchmaking.CreateLobby 异步完成后。
|
||||
// 成功判定:data.m_eResult == k_EResultOK。失败则不会进入房间,也不会再收到 LobbyEnter_t。
|
||||
// 用途:确认为房主,保存 LobbyID,设置 LobbyData / Rich Presence,然后等别人加入。
|
||||
private Callback<LobbyCreated_t> _cbLobbyCreated;
|
||||
|
||||
// 谁会收到:被邀请者、或通过好友资料 / 邀请链接 / Overlay 点"加入"你 Lobby 的玩家客户端。
|
||||
// 何时触发:玩家端点击接受邀请(或点击你在好友列表中的"加入游戏")后,Steam 向你的进程派发此回调。
|
||||
// 典型处理:立即调用 SteamMatchmaking.JoinLobby(data.m_steamIDLobby)。不代表已经进房,只是"请求加入"。
|
||||
private Callback<GameLobbyJoinRequested_t> _cbLobbyJoinRequested;
|
||||
|
||||
// 谁会收到:任意成功进入 Lobby 的客户端(包括创建者自己与每个加入者)。
|
||||
// 何时触发:JoinLobby(或 CreateLobby 成功后的内部自动加入)完成并真正加入成员列表后。
|
||||
// 作用:此时可读取成员列表 / LobbyData,更新 UI,开始建立 P2P。
|
||||
// 注意:创建者会先收到 LobbyCreated_t,随后收到自己的 LobbyEnter_t。被邀请者只会收到 GameLobbyJoinRequested_t →(调用 JoinLobby)→ LobbyEnter_t。
|
||||
private Callback<LobbyEnter_t> _cbLobbyEnter;
|
||||
|
||||
// 谁会收到:当前已在该 Lobby 中的所有成员。
|
||||
// 何时触发:成员进入、离开、断线、被踢、被封禁等成员列表变化时。可能多次。
|
||||
// 数据意义:data.m_ulSteamIDLobby = 目标 Lobby;data.m_ulSteamIDUserChanged = 发生变化的成员;data.m_ulSteamIDMakingChange = 触发者(踢人时是房主);data.m_rgfChatMemberStateChange 标志位指示加入/离开/踢/封禁等。
|
||||
// 用途:刷新成员 UI,迁移 Host(若房主离开), 清理对应的 P2P 连接。
|
||||
private Callback<LobbyChatUpdate_t> _cbLobbyChatUpdate;
|
||||
|
||||
// 初始化
|
||||
public void InitCallbacks()
|
||||
{
|
||||
_cbLobbyCreated = Callback<LobbyCreated_t>.Create(OnLobbyCreatedCallback);
|
||||
_cbLobbyJoinRequested = Callback<GameLobbyJoinRequested_t>.Create(OnLobbyJoinRequestedCallback);
|
||||
_cbLobbyEnter = Callback<LobbyEnter_t>.Create(OnLobbyEnterCallback);
|
||||
_cbLobbyChatUpdate = Callback<LobbyChatUpdate_t>.Create(OnLobbyChatUpdateCallback);
|
||||
|
||||
// 初始化P2P
|
||||
SimpleP2P.Instance.Initialize();
|
||||
|
||||
// 订阅P2P事件
|
||||
SimpleP2P.Instance.OnPeerConnectedEvent += OnP2PPeerConnected;
|
||||
SimpleP2P.Instance.OnPeerDisconnectedEvent += OnP2PPeerDisconnected;
|
||||
SimpleP2P.Instance.OnConnectionErrorEvent += OnP2PConnectionError;
|
||||
|
||||
LogSystem.LogInfo("SteamLobbyManager initialized");
|
||||
}
|
||||
|
||||
// 建房
|
||||
public void CreateFriendsLobby(int maxMembers = 4)
|
||||
{
|
||||
if (CurrentState != LobbyState.None)
|
||||
{
|
||||
LogSystem.LogInfo($"Cannot create lobby in state: {CurrentState}");
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentState = LobbyState.Creating;
|
||||
LogSystem.LogInfo($"Creating friends lobby with max members: {maxMembers}");
|
||||
SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, maxMembers);
|
||||
}
|
||||
|
||||
// 加入房间
|
||||
public void JoinLobby(CSteamID lobbyId)
|
||||
{
|
||||
if (CurrentState != LobbyState.None)
|
||||
{
|
||||
LogSystem.LogInfo($"Cannot join lobby in state: {CurrentState}");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo($"Joining lobby: {lobbyId}");
|
||||
CurrentState = LobbyState.Joining;
|
||||
SteamMatchmaking.JoinLobby(lobbyId);
|
||||
}
|
||||
|
||||
// 离开房间
|
||||
public void LeaveLobby()
|
||||
{
|
||||
if (!CurrentLobby.IsValid() || CurrentState == LobbyState.None) return;
|
||||
|
||||
CurrentState = LobbyState.Leaving;
|
||||
LogSystem.LogInfo("Leaving lobby");
|
||||
|
||||
// 断开所有P2P连接
|
||||
SimpleP2P.Instance.DisconnectAll();
|
||||
SteamMatchmaking.LeaveLobby(CurrentLobby);
|
||||
ResetLobbyState();
|
||||
}
|
||||
|
||||
// 解散房间(仅房主可用)
|
||||
public void DisbandLobby()
|
||||
{
|
||||
if (!IsLobbyOwner)
|
||||
{
|
||||
LogSystem.LogInfo("Only lobby owner can disband the lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo("Disbanding lobby");
|
||||
// 设置房间数据标记解散
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, "disbanded", "true");
|
||||
// 踢出所有其他成员
|
||||
foreach (var member in EnumerateMembers())
|
||||
{
|
||||
if (member != SteamUser.GetSteamID())
|
||||
{
|
||||
// Steam没有直接踢人API,通过设置数据让客户端自动离开
|
||||
SteamMatchmaking.SetLobbyMemberData(CurrentLobby, "kicked", "true");
|
||||
}
|
||||
}
|
||||
|
||||
// 房主最后离开
|
||||
LeaveLobby();
|
||||
}
|
||||
|
||||
// 踢出指定成员(仅房主可用)
|
||||
public void KickMember(CSteamID memberToKick)
|
||||
{
|
||||
if (!IsLobbyOwner)
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Only lobby owner can kick members");
|
||||
return;
|
||||
}
|
||||
|
||||
if (memberToKick == SteamUser.GetSteamID())
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Cannot kick yourself");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo($"Kicking member: {memberToKick}");
|
||||
|
||||
// 通过设置成员数据标记被踢,客户端检测到后自动离开
|
||||
SteamMatchmaking.SetLobbyMemberData(CurrentLobby, $"kick_{memberToKick.m_SteamID}", "true");
|
||||
}
|
||||
|
||||
// 邀请好友
|
||||
public void InviteFriend(CSteamID friendId)
|
||||
{
|
||||
if (!CurrentLobby.IsValid())
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Not in a lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo($"Inviting friend: {friendId}");
|
||||
SteamMatchmaking.InviteUserToLobby(CurrentLobby, friendId);
|
||||
}
|
||||
|
||||
// 打开好友邀请对话框
|
||||
public void OpenInviteOverlay()
|
||||
{
|
||||
if (!CurrentLobby.IsValid())
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Not in a lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
SteamFriends.ActivateGameOverlayInviteDialog(CurrentLobby);
|
||||
}
|
||||
|
||||
// 获取在线好友
|
||||
public List<(CSteamID id, string name)> GetOnlineFriends()
|
||||
{
|
||||
var list = new List<(CSteamID, string)>();
|
||||
int count = SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var fid = SteamFriends.GetFriendByIndex(i, EFriendFlags.k_EFriendFlagImmediate);
|
||||
var state = SteamFriends.GetFriendPersonaState(fid);
|
||||
if (state == EPersonaState.k_EPersonaStateOnline ||
|
||||
state == EPersonaState.k_EPersonaStateAway ||
|
||||
state == EPersonaState.k_EPersonaStateBusy ||
|
||||
state == EPersonaState.k_EPersonaStateSnooze)
|
||||
{
|
||||
list.Add((fid, SteamFriends.GetFriendPersonaName(fid)));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// 设置房间数据
|
||||
public void SetLobbyData(string key, string value)
|
||||
{
|
||||
if (!IsLobbyOwner)
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Only lobby owner can set lobby data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CurrentLobby.IsValid()) return;
|
||||
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, key, value);
|
||||
}
|
||||
|
||||
// 获取房间数据
|
||||
public string GetLobbyData(string key)
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return "";
|
||||
return SteamMatchmaking.GetLobbyData(CurrentLobby, key);
|
||||
}
|
||||
|
||||
// 房间创建回调
|
||||
private void OnLobbyCreatedCallback(LobbyCreated_t data)
|
||||
{
|
||||
if (data.m_eResult != EResult.k_EResultOK)
|
||||
{
|
||||
CurrentState = LobbyState.None;
|
||||
OnLobbyErrorEvent?.Invoke($"Failed to create lobby: {data.m_eResult}");
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentLobby = new CSteamID(data.m_ulSteamIDLobby);
|
||||
CachedOwner = SteamUser.GetSteamID();
|
||||
|
||||
LogSystem.LogInfo($"Lobby created successfully: {CurrentLobby}");
|
||||
|
||||
// 设置房间基础数据
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, "owner", SteamUser.GetSteamID().m_SteamID.ToString());
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, "version", "1.0");
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, "game_mode", "default");
|
||||
|
||||
// 设置Rich Presence
|
||||
SteamFriends.SetRichPresence("connect", "+connect_lobby " + CurrentLobby.m_SteamID);
|
||||
SteamFriends.SetRichPresence("status", "In Lobby");
|
||||
|
||||
OnLobbyCreatedEvent?.Invoke(CurrentLobby);
|
||||
}
|
||||
|
||||
// 加入请求回调
|
||||
private void OnLobbyJoinRequestedCallback(GameLobbyJoinRequested_t data)
|
||||
{
|
||||
LogSystem.LogInfo($"Join requested for lobby: {data.m_steamIDLobby}");
|
||||
|
||||
// 检查是否被踢或房间被解散
|
||||
var disbandedData = SteamMatchmaking.GetLobbyData(data.m_steamIDLobby, "disbanded");
|
||||
if (disbandedData == "true")
|
||||
{
|
||||
LogSystem.LogInfo($"Cannot join disbanded lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
JoinLobby(data.m_steamIDLobby);
|
||||
}
|
||||
|
||||
// 进入房间回调
|
||||
private void OnLobbyEnterCallback(LobbyEnter_t data)
|
||||
{
|
||||
// 检查加入结果
|
||||
if ((EChatRoomEnterResponse)data.m_EChatRoomEnterResponse != EChatRoomEnterResponse.k_EChatRoomEnterResponseSuccess)
|
||||
{
|
||||
CurrentState = LobbyState.None;
|
||||
LogSystem.LogError($"Failed to enter lobby: {(EChatRoomEnterResponse)data.m_EChatRoomEnterResponse}");
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentLobby = new CSteamID(data.m_ulSteamIDLobby);
|
||||
CachedOwner = SteamMatchmaking.GetLobbyOwner(CurrentLobby);
|
||||
CurrentState = LobbyState.InLobby;
|
||||
|
||||
LogSystem.LogInfo($"Successfully entered lobby: {CurrentLobby}");
|
||||
|
||||
// 检查是否被踢
|
||||
CheckIfKicked();
|
||||
OnLobbyReadyInternal();
|
||||
OnLobbyMembersChangedInternal();
|
||||
}
|
||||
|
||||
// 成员变化回调
|
||||
private void OnLobbyChatUpdateCallback(LobbyChatUpdate_t data)
|
||||
{
|
||||
if (data.m_ulSteamIDLobby != CurrentLobby.m_SteamID) return;
|
||||
|
||||
var changedUser = new CSteamID(data.m_ulSteamIDUserChanged);
|
||||
var stateChange = (EChatMemberStateChange)data.m_rgfChatMemberStateChange;
|
||||
|
||||
LogSystem.LogInfo($"Lobby member update: {changedUser} - {stateChange}");
|
||||
|
||||
// 处理成员状态变化
|
||||
if (stateChange.HasFlag(EChatMemberStateChange.k_EChatMemberStateChangeEntered))
|
||||
{
|
||||
OnMemberJoinedEvent?.Invoke(changedUser);
|
||||
|
||||
// 如果我是房主,尝试连接到新成员
|
||||
if (IsLobbyOwner && changedUser != SteamUser.GetSteamID())
|
||||
{
|
||||
SimpleP2P.Instance.ConnectToPeer(changedUser);
|
||||
}
|
||||
}
|
||||
else if (stateChange.HasFlag(EChatMemberStateChange.k_EChatMemberStateChangeLeft) ||
|
||||
stateChange.HasFlag(EChatMemberStateChange.k_EChatMemberStateChangeDisconnected) ||
|
||||
stateChange.HasFlag(EChatMemberStateChange.k_EChatMemberStateChangeKicked) ||
|
||||
stateChange.HasFlag(EChatMemberStateChange.k_EChatMemberStateChangeBanned))
|
||||
{
|
||||
OnMemberLeftEvent?.Invoke(changedUser);
|
||||
|
||||
// 断开P2P连接
|
||||
SimpleP2P.Instance.DisconnectFromPeer(changedUser);
|
||||
}
|
||||
|
||||
OnLobbyMembersChangedInternal();
|
||||
CheckOwnerChange();
|
||||
}
|
||||
|
||||
// 检查房主变化
|
||||
private void CheckOwnerChange()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return;
|
||||
|
||||
var currentOwner = SteamMatchmaking.GetLobbyOwner(CurrentLobby);
|
||||
if (!CachedOwner.IsValid())
|
||||
{
|
||||
CachedOwner = currentOwner;
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentOwner != CachedOwner)
|
||||
{
|
||||
var oldOwner = CachedOwner;
|
||||
CachedOwner = currentOwner;
|
||||
|
||||
LogSystem.LogInfo($"Host changed from {oldOwner} to {currentOwner}");
|
||||
|
||||
OnHostChangedEvent?.Invoke(oldOwner, currentOwner);
|
||||
OnHostChangedInternal();
|
||||
}
|
||||
}
|
||||
|
||||
// 房主切换时内部处理
|
||||
private void OnHostChangedInternal()
|
||||
{
|
||||
if (IsLobbyOwner)
|
||||
{
|
||||
LogSystem.LogInfo("I became the new host");
|
||||
|
||||
// 新房主连接到所有其他成员
|
||||
foreach (var member in EnumerateMembers())
|
||||
{
|
||||
if (member != SteamUser.GetSteamID())
|
||||
{
|
||||
SimpleP2P.Instance.ConnectToPeer(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSystem.LogInfo($"New host is: {CachedOwner}");
|
||||
|
||||
// 普通成员断开旧连接,连接新房主
|
||||
SimpleP2P.Instance.DisconnectAll();
|
||||
SimpleP2P.Instance.ConnectToPeer(CachedOwner);
|
||||
}
|
||||
}
|
||||
|
||||
// 房间准备完毕时内部处理
|
||||
private void OnLobbyReadyInternal()
|
||||
{
|
||||
// 如果不是房主,连接到房主
|
||||
if (!IsLobbyOwner && CachedOwner.IsValid())
|
||||
{
|
||||
SimpleP2P.Instance.ConnectToPeer(CachedOwner);
|
||||
}
|
||||
}
|
||||
|
||||
// 有成员变化时内部处理
|
||||
private void OnLobbyMembersChangedInternal()
|
||||
{
|
||||
var members = EnumerateMembers().ToList();
|
||||
LogSystem.LogInfo($"Lobby members changed. Count: {members.Count}");
|
||||
OnMembersChangedEvent?.Invoke(members);
|
||||
}
|
||||
|
||||
// 检查是否被踢
|
||||
private void CheckIfKicked()
|
||||
{
|
||||
var kickData = SteamMatchmaking.GetLobbyMemberData(CurrentLobby, SteamUser.GetSteamID(), "kicked");
|
||||
var specificKick = SteamMatchmaking.GetLobbyData(CurrentLobby, $"kick_{SteamUser.GetSteamID().m_SteamID}");
|
||||
|
||||
if (kickData == "true" || specificKick == "true")
|
||||
{
|
||||
LogSystem.LogInfo("I was kicked from the lobby");
|
||||
LeaveLobby();
|
||||
}
|
||||
}
|
||||
|
||||
// 重置房间状态
|
||||
private void ResetLobbyState()
|
||||
{
|
||||
CurrentLobby = CSteamID.Nil;
|
||||
CachedOwner = CSteamID.Nil;
|
||||
CurrentState = LobbyState.None;
|
||||
|
||||
// 清除Rich Presence
|
||||
SteamFriends.ClearRichPresence();
|
||||
}
|
||||
|
||||
// P2P事件处理
|
||||
private void OnP2PPeerConnected(CSteamID steamID)
|
||||
{
|
||||
LogSystem.LogInfo($"P2P connection established with: {steamID}");
|
||||
}
|
||||
|
||||
private void OnP2PPeerDisconnected(CSteamID steamID)
|
||||
{
|
||||
LogSystem.LogInfo($"P2P connection lost with: {steamID}");
|
||||
}
|
||||
|
||||
private void OnP2PConnectionError(string error)
|
||||
{
|
||||
LogSystem.LogError($"P2P connection error: {error}");
|
||||
}
|
||||
|
||||
// 发送P2P消息
|
||||
public bool SendMessageToPeer(CSteamID target, byte[] data, bool reliable = true)
|
||||
{
|
||||
if (!IsInLobby)
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Not in lobby");
|
||||
return false;
|
||||
}
|
||||
|
||||
return SimpleP2P.Instance.SendTo(target, data, reliable);
|
||||
}
|
||||
|
||||
// 广播P2P消息
|
||||
public void BroadcastMessage(byte[] data, bool reliable = true)
|
||||
{
|
||||
if (!IsInLobby)
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Not in lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleP2P.Instance.Broadcast(data, reliable);
|
||||
}
|
||||
|
||||
// 轮询P2P消息(需要在Update中调用)
|
||||
public void Update()
|
||||
{
|
||||
SimpleP2P.Instance.PollMessages();
|
||||
}
|
||||
|
||||
// 枚举房间成员
|
||||
public IEnumerable<CSteamID> EnumerateMembers()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) yield break;
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
for (int i = 0; i < count; i++)
|
||||
yield return SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
|
||||
}
|
||||
|
||||
// 获取成员数量
|
||||
public int GetMemberCount()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return 0;
|
||||
return SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
}
|
||||
|
||||
// 获取最大成员数
|
||||
public int GetMemberLimit()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return 0;
|
||||
return SteamMatchmaking.GetLobbyMemberLimit(CurrentLobby);
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
public void Cleanup()
|
||||
{
|
||||
LeaveLobby();
|
||||
SimpleP2P.Instance.Cleanup();
|
||||
|
||||
_cbLobbyCreated?.Dispose();
|
||||
_cbLobbyJoinRequested?.Dispose();
|
||||
_cbLobbyEnter?.Dispose();
|
||||
_cbLobbyChatUpdate?.Dispose();
|
||||
|
||||
LogSystem.LogInfo("SteamLobbyManager cleaned up");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* @Author: 白哉
|
||||
* @Description:
|
||||
* @Date: 2025年05月26日 星期一 14:05:31
|
||||
* @Modify:
|
||||
*/
|
||||
|
||||
|
||||
using UnityEngine;
|
||||
using Steamworks;
|
||||
using System;
|
||||
|
||||
|
||||
namespace Logic.SteamManager
|
||||
{
|
||||
public class SteamManager
|
||||
{
|
||||
public static SteamManager Instance = new SteamManager();
|
||||
|
||||
public void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
440
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestManager.cs
Normal file
440
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestManager.cs
Normal file
@ -0,0 +1,440 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using Steamworks;
|
||||
using TH1_Logic.Steam;
|
||||
using Logic.CrashSight;
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam测试管理器 - 用于在Unity编辑器中测试Steam功能
|
||||
/// </summary>
|
||||
public class SteamTestManager : MonoBehaviour
|
||||
{
|
||||
[Header("Steam 连接状态")]
|
||||
public bool IsSteamInitialized = false;
|
||||
public bool IsLoggedIn = false;
|
||||
public string CurrentUserName = "";
|
||||
public CSteamID CurrentUserID;
|
||||
|
||||
[Header("测试配置")]
|
||||
[SerializeField] private bool autoInitialize = true;
|
||||
[SerializeField] private bool enableDebugLog = true;
|
||||
|
||||
[Header("房间测试")]
|
||||
[SerializeField] private int maxLobbyMembers = 4;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 确保只有一个实例
|
||||
if (FindObjectsOfType<SteamTestManager>().Length > 1)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (autoInitialize)
|
||||
{
|
||||
StartCoroutine(InitializeSteam());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化Steam
|
||||
/// </summary>
|
||||
private IEnumerator InitializeSteam()
|
||||
{
|
||||
LogSystem.LogInfo("开始初始化Steam...");
|
||||
LogSystem.LogInfo($"启动方式检测: {(SteamAPI.RestartAppIfNecessary(new Steamworks.AppId_t(480)) ? "需要通过Steam启动" : "直接启动或已通过Steam启动")}");
|
||||
|
||||
// 检查Steam是否运行
|
||||
if (!SteamAPI.IsSteamRunning())
|
||||
{
|
||||
LogSystem.LogError("Steam客户端未运行!请先启动Steam。");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 检查steam_appid.txt文件状态
|
||||
CheckSteamAppIdFile();
|
||||
|
||||
// 初始化Steam API
|
||||
IsSteamInitialized = SteamAPI.Init();
|
||||
|
||||
if (!IsSteamInitialized)
|
||||
{
|
||||
LogSystem.LogError("Steam API初始化失败!");
|
||||
LogSystem.LogError("可能的原因:");
|
||||
LogSystem.LogError("1. Steam客户端未运行");
|
||||
LogSystem.LogError("2. steam_appid.txt文件配置错误(开发环境)");
|
||||
LogSystem.LogError("3. 没有以Steam方式启动应用(开发环境)");
|
||||
LogSystem.LogError("4. Steam App ID不匹配");
|
||||
yield break;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo("Steam API初始化成功!");
|
||||
|
||||
// 等待一帧确保Steam完全初始化
|
||||
yield return null;
|
||||
|
||||
// 检查用户登录状态
|
||||
try
|
||||
{
|
||||
CheckUserLoginStatus();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
LogSystem.LogError($"检查用户登录状态异常: {e.Message}");
|
||||
}
|
||||
|
||||
// 显示启动信息
|
||||
DisplayLaunchInfo();
|
||||
|
||||
// 初始化Steam房间管理器
|
||||
try
|
||||
{
|
||||
InitializeSteamLobbyManager();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
LogSystem.LogError($"Steam房间管理器初始化异常: {e.Message}");
|
||||
}
|
||||
|
||||
LogSystem.LogInfo("Steam测试环境初始化完成!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查steam_appid.txt文件状态
|
||||
/// </summary>
|
||||
private void CheckSteamAppIdFile()
|
||||
{
|
||||
string steamAppIdPath = Path.Combine(Directory.GetCurrentDirectory(), "steam_appid.txt");
|
||||
|
||||
if (File.Exists(steamAppIdPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
string content = File.ReadAllText(steamAppIdPath).Trim();
|
||||
LogSystem.LogInfo($"发现steam_appid.txt文件,App ID: {content}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
LogSystem.LogWarning($"读取steam_appid.txt失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSystem.LogInfo("未发现steam_appid.txt文件 - 这在Steam平台发布时是正常的");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示启动信息
|
||||
/// </summary>
|
||||
private void DisplayLaunchInfo()
|
||||
{
|
||||
if (!IsSteamInitialized) return;
|
||||
|
||||
// 获取当前App ID
|
||||
var currentAppId = SteamUtils.GetAppID();
|
||||
LogSystem.LogInfo($"当前Steam App ID: {currentAppId}");
|
||||
|
||||
// 检查启动方式
|
||||
bool launchedViaSteam = SteamApps.BIsSubscribedApp(currentAppId);
|
||||
LogSystem.LogInfo($"通过Steam启动: {(launchedViaSteam ? "是" : "否")}");
|
||||
|
||||
// 显示Steam环境信息
|
||||
LogSystem.LogInfo($"Steam语言: {SteamApps.GetCurrentGameLanguage()}");
|
||||
LogSystem.LogInfo($"Steam服务器连接: {(SteamUser.BLoggedOn() ? "已连接" : "未连接")}");
|
||||
|
||||
// 检查DLC和订阅状态
|
||||
if (currentAppId.m_AppId == 480) // Spacewar测试应用
|
||||
{
|
||||
LogSystem.LogInfo("当前使用Spacewar测试应用 - 适用于开发测试");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSystem.LogInfo($"当前使用正式应用ID: {currentAppId.m_AppId}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查用户登录状态
|
||||
/// </summary>
|
||||
private void CheckUserLoginStatus()
|
||||
{
|
||||
if (!IsSteamInitialized) return;
|
||||
|
||||
IsLoggedIn = SteamUser.BLoggedOn();
|
||||
|
||||
if (IsLoggedIn)
|
||||
{
|
||||
CurrentUserID = SteamUser.GetSteamID();
|
||||
CurrentUserName = SteamFriends.GetPersonaName();
|
||||
LogSystem.LogInfo($"Steam用户已登录: {CurrentUserName} ({CurrentUserID})");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSystem.LogWarning("Steam用户未登录");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化Steam房间管理器
|
||||
/// </summary>
|
||||
private void InitializeSteamLobbyManager()
|
||||
{
|
||||
if (!IsSteamInitialized || !IsLoggedIn) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 初始化房间管理器
|
||||
SteamLobbyManager.Instance.InitCallbacks();
|
||||
|
||||
// 订阅事件
|
||||
SteamLobbyManager.Instance.OnLobbyCreatedEvent += OnLobbyCreated;
|
||||
SteamLobbyManager.Instance.OnLobbyEnteredEvent += OnLobbyEntered;
|
||||
SteamLobbyManager.Instance.OnLobbyLeftEvent += OnLobbyLeft;
|
||||
SteamLobbyManager.Instance.OnMemberJoinedEvent += OnMemberJoined;
|
||||
SteamLobbyManager.Instance.OnMemberLeftEvent += OnMemberLeft;
|
||||
SteamLobbyManager.Instance.OnHostChangedEvent += OnHostChanged;
|
||||
SteamLobbyManager.Instance.OnLobbyErrorEvent += OnLobbyError;
|
||||
|
||||
// 订阅P2P事件
|
||||
SimpleP2P.Instance.OnPeerConnectedEvent += OnP2PPeerConnected;
|
||||
SimpleP2P.Instance.OnPeerDisconnectedEvent += OnP2PPeerDisconnected;
|
||||
SimpleP2P.Instance.OnMessageReceivedEvent += OnP2PMessageReceived;
|
||||
SimpleP2P.Instance.OnConnectionErrorEvent += OnP2PConnectionError;
|
||||
|
||||
LogSystem.LogInfo("Steam房间管理器初始化成功!");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
LogSystem.LogError($"Steam房间管理器初始化失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (IsSteamInitialized)
|
||||
{
|
||||
// 更新Steam回调
|
||||
SteamAPI.RunCallbacks();
|
||||
|
||||
// 更新P2P消息
|
||||
SteamLobbyManager.Instance.Update();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (IsSteamInitialized)
|
||||
{
|
||||
SteamLobbyManager.Instance.Cleanup();
|
||||
SteamAPI.Shutdown();
|
||||
LogSystem.LogInfo("Steam API已关闭");
|
||||
}
|
||||
}
|
||||
|
||||
#region 房间事件处理
|
||||
|
||||
private void OnLobbyCreated(CSteamID lobbyId)
|
||||
{
|
||||
LogSystem.LogInfo($"[测试] 房间创建成功: {lobbyId}");
|
||||
}
|
||||
|
||||
private void OnLobbyEntered(CSteamID lobbyId)
|
||||
{
|
||||
LogSystem.LogInfo($"[测试] 进入房间: {lobbyId}");
|
||||
LogSystem.LogInfo($"[测试] 房间成员数: {SteamLobbyManager.Instance.GetMemberCount()}/{SteamLobbyManager.Instance.GetMemberLimit()}");
|
||||
}
|
||||
|
||||
private void OnLobbyLeft()
|
||||
{
|
||||
LogSystem.LogInfo("[测试] 离开房间");
|
||||
}
|
||||
|
||||
private void OnMemberJoined(CSteamID memberId)
|
||||
{
|
||||
string memberName = SteamFriends.GetFriendPersonaName(memberId);
|
||||
LogSystem.LogInfo($"[测试] 成员加入: {memberName} ({memberId})");
|
||||
}
|
||||
|
||||
private void OnMemberLeft(CSteamID memberId)
|
||||
{
|
||||
string memberName = SteamFriends.GetFriendPersonaName(memberId);
|
||||
LogSystem.LogInfo($"[测试] 成员离开: {memberName} ({memberId})");
|
||||
}
|
||||
|
||||
private void OnHostChanged(CSteamID oldHost, CSteamID newHost)
|
||||
{
|
||||
string oldHostName = SteamFriends.GetFriendPersonaName(oldHost);
|
||||
string newHostName = SteamFriends.GetFriendPersonaName(newHost);
|
||||
LogSystem.LogInfo($"[测试] 房主变更: {oldHostName} -> {newHostName}");
|
||||
}
|
||||
|
||||
private void OnLobbyError(string error)
|
||||
{
|
||||
LogSystem.LogError($"[测试] 房间错误: {error}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region P2P事件处理
|
||||
|
||||
private void OnP2PPeerConnected(CSteamID peerId)
|
||||
{
|
||||
string peerName = SteamFriends.GetFriendPersonaName(peerId);
|
||||
LogSystem.LogInfo($"[测试] P2P连接建立: {peerName} ({peerId})");
|
||||
}
|
||||
|
||||
private void OnP2PPeerDisconnected(CSteamID peerId)
|
||||
{
|
||||
string peerName = SteamFriends.GetFriendPersonaName(peerId);
|
||||
LogSystem.LogInfo($"[测试] P2P连接断开: {peerName} ({peerId})");
|
||||
}
|
||||
|
||||
private void OnP2PMessageReceived(CSteamID senderId, byte[] data)
|
||||
{
|
||||
string senderName = SteamFriends.GetFriendPersonaName(senderId);
|
||||
string message = System.Text.Encoding.UTF8.GetString(data);
|
||||
LogSystem.LogInfo($"[测试] 收到P2P消息 from {senderName}: {message}");
|
||||
}
|
||||
|
||||
private void OnP2PConnectionError(string error)
|
||||
{
|
||||
LogSystem.LogError($"[测试] P2P连接错误: {error}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测试方法 - 可在Inspector中调用
|
||||
|
||||
[ContextMenu("创建测试房间")]
|
||||
public void TestCreateLobby()
|
||||
{
|
||||
if (!CanPerformLobbyAction()) return;
|
||||
|
||||
LogSystem.LogInfo("[测试] 创建房间...");
|
||||
SteamLobbyManager.Instance.CreateFriendsLobby(maxLobbyMembers);
|
||||
}
|
||||
|
||||
[ContextMenu("离开房间")]
|
||||
public void TestLeaveLobby()
|
||||
{
|
||||
if (!SteamLobbyManager.Instance.IsInLobby)
|
||||
{
|
||||
LogSystem.LogWarning("[测试] 当前不在房间中");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo("[测试] 离开房间...");
|
||||
SteamLobbyManager.Instance.LeaveLobby();
|
||||
}
|
||||
|
||||
[ContextMenu("发送测试消息")]
|
||||
public void TestSendMessage()
|
||||
{
|
||||
if (!SteamLobbyManager.Instance.IsInLobby)
|
||||
{
|
||||
LogSystem.LogWarning("[测试] 当前不在房间中,无法发送消息");
|
||||
return;
|
||||
}
|
||||
|
||||
string testMessage = $"测试消息 from {CurrentUserName} at {System.DateTime.Now:HH:mm:ss}";
|
||||
byte[] data = System.Text.Encoding.UTF8.GetBytes(testMessage);
|
||||
|
||||
LogSystem.LogInfo($"[测试] 广播消息: {testMessage}");
|
||||
SteamLobbyManager.Instance.BroadcastMessage(data, true);
|
||||
}
|
||||
|
||||
[ContextMenu("显示在线好友")]
|
||||
public void TestShowOnlineFriends()
|
||||
{
|
||||
if (!CanPerformLobbyAction()) return;
|
||||
|
||||
var friends = SteamLobbyManager.Instance.GetOnlineFriends();
|
||||
LogSystem.LogInfo($"[测试] 在线好友数量: {friends.Count}");
|
||||
|
||||
foreach (var friend in friends)
|
||||
{
|
||||
LogSystem.LogInfo($"[测试] 好友: {friend.name} ({friend.id})");
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("打开邀请界面")]
|
||||
public void TestOpenInviteOverlay()
|
||||
{
|
||||
if (!SteamLobbyManager.Instance.IsInLobby)
|
||||
{
|
||||
LogSystem.LogWarning("[测试] 当前不在房间中,无法邀请好友");
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo("[测试] 打开Steam邀请界面...");
|
||||
SteamLobbyManager.Instance.OpenInviteOverlay();
|
||||
}
|
||||
|
||||
private bool CanPerformLobbyAction()
|
||||
{
|
||||
if (!IsSteamInitialized)
|
||||
{
|
||||
LogSystem.LogError("[测试] Steam未初始化");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsLoggedIn)
|
||||
{
|
||||
LogSystem.LogError("[测试] Steam用户未登录");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GUI显示状态
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!enableDebugLog) return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 10, 300, 400));
|
||||
GUILayout.BeginVertical("box");
|
||||
|
||||
GUILayout.Label("Steam 测试状态", GUI.skin.label);
|
||||
GUILayout.Label($"Steam初始化: {(IsSteamInitialized ? "✓" : "✗")}");
|
||||
GUILayout.Label($"用户登录: {(IsLoggedIn ? "✓" : "✗")}");
|
||||
|
||||
if (IsLoggedIn)
|
||||
{
|
||||
GUILayout.Label($"用户: {CurrentUserName}");
|
||||
GUILayout.Label($"ID: {CurrentUserID}");
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.Label("房间状态", GUI.skin.label);
|
||||
GUILayout.Label($"当前状态: {SteamLobbyManager.Instance.CurrentState}");
|
||||
GUILayout.Label($"在房间中: {(SteamLobbyManager.Instance.IsInLobby ? "✓" : "✗")}");
|
||||
GUILayout.Label($"是房主: {(SteamLobbyManager.Instance.IsLobbyOwner ? "✓" : "✗")}");
|
||||
|
||||
if (SteamLobbyManager.Instance.IsInLobby)
|
||||
{
|
||||
GUILayout.Label($"房间ID: {SteamLobbyManager.Instance.CurrentLobby}");
|
||||
GUILayout.Label($"成员数: {SteamLobbyManager.Instance.GetMemberCount()}/{SteamLobbyManager.Instance.GetMemberLimit()}");
|
||||
GUILayout.Label($"P2P连接数: {SimpleP2P.Instance.GetConnectionCount()}");
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d8d18aba4f448e095c425fe5a24a1c8
|
||||
timeCreated: 1756803052
|
||||
125
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestUI.cs
Normal file
125
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestUI.cs
Normal file
@ -0,0 +1,125 @@
|
||||
// using UnityEngine;
|
||||
// using UnityEngine.UI;
|
||||
// using Logic.CrashSight;
|
||||
//
|
||||
//
|
||||
// namespace TH1_Logic.Steam
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// Steam测试UI - 提供简单的UI界面来测试Steam功能
|
||||
// /// </summary>
|
||||
// public class SteamTestUI : MonoBehaviour
|
||||
// {
|
||||
// [Header("UI组件")]
|
||||
// public Button createLobbyButton;
|
||||
// public Button leaveLobbyButton;
|
||||
// public Button sendMessageButton;
|
||||
// public Button showFriendsButton;
|
||||
// public Button inviteButton;
|
||||
// public Text statusText;
|
||||
// public Text lobbyInfoText;
|
||||
// public InputField messageInput;
|
||||
//
|
||||
// private SteamTestManager steamTestManager;
|
||||
//
|
||||
// private void Start()
|
||||
// {
|
||||
// steamTestManager = FindObjectOfType<SteamTestManager>();
|
||||
// if (steamTestManager == null)
|
||||
// {
|
||||
// LogSystem.LogError("找不到SteamTestManager组件!");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// SetupUI();
|
||||
// }
|
||||
//
|
||||
// private void SetupUI()
|
||||
// {
|
||||
// if (createLobbyButton) createLobbyButton.onClick.AddListener(OnCreateLobby);
|
||||
// if (leaveLobbyButton) leaveLobbyButton.onClick.AddListener(OnLeaveLobby);
|
||||
// if (sendMessageButton) sendMessageButton.onClick.AddListener(OnSendMessage);
|
||||
// if (showFriendsButton) showFriendsButton.onClick.AddListener(OnShowFriends);
|
||||
// if (inviteButton) inviteButton.onClick.AddListener(OnInviteFriends);
|
||||
//
|
||||
// if (messageInput) messageInput.text = "Hello Steam P2P!";
|
||||
// }
|
||||
//
|
||||
// private void Update()
|
||||
// {
|
||||
// UpdateUI();
|
||||
// }
|
||||
//
|
||||
// private void UpdateUI()
|
||||
// {
|
||||
// if (!steamTestManager) return;
|
||||
//
|
||||
// // 更新状态文本
|
||||
// if (statusText)
|
||||
// {
|
||||
// statusText.text = $"Steam: {(steamTestManager.IsSteamInitialized ? "✓" : "✗")} | " +
|
||||
// $"登录: {(steamTestManager.IsLoggedIn ? "✓" : "✗")} | " +
|
||||
// $"用户: {steamTestManager.CurrentUserName}";
|
||||
// }
|
||||
//
|
||||
// // 更新房间信息
|
||||
// if (lobbyInfoText)
|
||||
// {
|
||||
// var lobby = SteamLobbyManager.Instance;
|
||||
// lobbyInfoText.text = $"状态: {lobby.CurrentState}\n" +
|
||||
// $"在房间: {(lobby.IsInLobby ? "✓" : "✗")}\n" +
|
||||
// $"是房主: {(lobby.IsLobbyOwner ? "✓" : "✗")}\n" +
|
||||
// $"成员数: {lobby.GetMemberCount()}/{lobby.GetMemberLimit()}\n" +
|
||||
// $"P2P连接: {SimpleP2P.Instance.GetConnectionCount()}";
|
||||
// }
|
||||
//
|
||||
// // 更新按钮状态
|
||||
// bool canCreateLobby = steamTestManager.IsSteamInitialized &&
|
||||
// steamTestManager.IsLoggedIn &&
|
||||
// !SteamLobbyManager.Instance.IsInLobby;
|
||||
//
|
||||
// bool inLobby = SteamLobbyManager.Instance.IsInLobby;
|
||||
//
|
||||
// if (createLobbyButton) createLobbyButton.interactable = canCreateLobby;
|
||||
// if (leaveLobbyButton) leaveLobbyButton.interactable = inLobby;
|
||||
// if (sendMessageButton) sendMessageButton.interactable = inLobby;
|
||||
// if (inviteButton) inviteButton.interactable = inLobby;
|
||||
// if (showFriendsButton) showFriendsButton.interactable = steamTestManager.IsSteamInitialized && steamTestManager.IsLoggedIn;
|
||||
// }
|
||||
//
|
||||
// public void OnCreateLobby()
|
||||
// {
|
||||
// steamTestManager.TestCreateLobby();
|
||||
// }
|
||||
//
|
||||
// public void OnLeaveLobby()
|
||||
// {
|
||||
// steamTestManager.TestLeaveLobby();
|
||||
// }
|
||||
//
|
||||
// public void OnSendMessage()
|
||||
// {
|
||||
// if (messageInput && !string.IsNullOrEmpty(messageInput.text))
|
||||
// {
|
||||
// string message = $"{steamTestManager.CurrentUserName}: {messageInput.text}";
|
||||
// byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
|
||||
// SteamLobbyManager.Instance.BroadcastMessage(data, true);
|
||||
// LogSystem.LogInfo($"发送消息: {message}");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// steamTestManager.TestSendMessage();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void OnShowFriends()
|
||||
// {
|
||||
// steamTestManager.TestShowOnlineFriends();
|
||||
// }
|
||||
//
|
||||
// public void OnInviteFriends()
|
||||
// {
|
||||
// steamTestManager.TestOpenInviteOverlay();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestUI.cs.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Steam/SteamTestUI.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dee2e67a5e7243edbd18fd09ef135a55
|
||||
timeCreated: 1756803150
|
||||
@ -0,0 +1,2 @@
|
||||
480
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user