说明
希望有生之年能在Steam
发售一款无服务器的联机游戏。
在寻找解决方案时找到了Mirror
,不过好像已经停止更新了。故而寻找新的替代品,此时,FishNet
进入了我的视野。FishNet
拥有非常活跃的社区以及解决方案。在FishNet
的基础上,使用社区扩展的FishySteamworks
进行连接的扩展,可以不需要通过外网IP也可以直接通过Steam进行数据交换。
项目引用
FishNet
Steamworks.NET
FishySteamworks
简单例子
- 导入包后,在包里找到
NetworkManager
,直接丢入场景。 - 创建一个游戏对象,附加
NetworkObject
和NetworkTransform
,拖入NetworkManager
的PlayerSpawner
的PlayerPrefabs
。 - 启动后可以看到服务器和客户端的按钮,启动服务器后启动客户端即可看到玩家预制体被克隆出来,从局域网启动就可以了。
- 连接
Steam
还需要在NetworkManager
附加FishySteamworks
组件,该组件是继承自FishNet
的连接组件Transport
。还需要编写SteamSDK
的相关代码如下:
#if UNITY_STANDALONE_WIN
/*********************************************
* BFramework
* SteamSDK工具类
* 创建时间:2023/12/27 17:43:00
*********************************************/
using FishySteamworks;
using Framework;
using Steamworks;
using System;
namespace GameData
{
/// <summary>
/// SteamSDK工具类
/// </summary>
public class SteamSDKHelper : GameBase
{
/// <summary>
/// Steam和FishNet网络中转器
/// </summary>
private FishySteamworks.FishySteamworks _fishySteamworks;
public void InitFishySteamworks(FishySteamworks.FishySteamworks fishySteamworks) => _fishySteamworks = fishySteamworks;
private const string _hostAddressKey = "HostAddress";
private string _hostAddressValue;
public SteamSDKHelper()
{
InitSteamCallback();
}
#region Callback
/// <summary>
/// 创建大厅回调
/// </summary>
private Callback<LobbyCreated_t> _lobbyCreatedCallback;
/// <summary>
/// 从大厅加入游戏的回调
/// </summary>
private Callback<GameLobbyJoinRequested_t> _gameLobbyJoinRequestedCallback;
/// <summary>
/// 加入大厅后的回调
/// </summary>
private Callback<LobbyEnter_t> _lobbyEnterCallback;
/// <summary>
/// 初始化Steam监听回调
/// </summary>
private void InitSteamCallback()
{
_lobbyCreatedCallback = Callback<LobbyCreated_t>.Create(LobbyCreatedCallback);
_gameLobbyJoinRequestedCallback = Callback<GameLobbyJoinRequested_t>.Create(GameLobbyJoinRequestedCallback);
_lobbyEnterCallback = Callback<LobbyEnter_t>.Create(LobbyEnterCallback);
}
/// <summary>
/// 创建大厅回调
/// </summary>
private void LobbyCreatedCallback(LobbyCreated_t result)
{
if (result.m_eResult != EResult.k_EResultOK)
{
LogError("Steam大厅创建失败!");
return;
}
Log("Steam大厅创建成功!");
//设置大厅数据
_hostAddressValue = SteamUser.GetSteamID().ToString();
SteamMatchmaking.SetLobbyData(new CSteamID(result.m_ulSteamIDLobby), _hostAddressKey, _hostAddressValue);
_fishySteamworks.SetClientAddress(_hostAddressValue);
_fishySteamworks.StartConnection(true);
}
/// <summary>
/// 从好友列表中加入大厅时调用
/// </summary>
private void GameLobbyJoinRequestedCallback(GameLobbyJoinRequested_t result)
{
SteamMatchmaking.JoinLobby(result.m_steamIDLobby);
Log("Steam好友尝试从好友列表加入!");
}
/// <summary>
/// 加入大厅后的回调
/// </summary>
private void LobbyEnterCallback(LobbyEnter_t result)
{
string hostAddress = SteamMatchmaking.GetLobbyData(new CSteamID(result.m_ulSteamIDLobby), _hostAddressKey);
_fishySteamworks.SetClientAddress(hostAddress);
_fishySteamworks.StartConnection(false);
}
#endregion
/// <summary>
/// 创建大厅
/// </summary>
public void CreateLobby()
{
if (!SteamManager.Initialized)
{
LogError("Steam未初始化");
return;
}
SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, GameData.ConstDefine.RoomMaxPeople);
}
}
}
#endif
- 到此,用户创建或连接
Steam
大厅并进行数据同步就大功告成了。
已知问题
FishNet
所有的脚本,如果使用AB包克隆会丢失记录UID的表对象(原因不明),而Resource
加载不会。所以不支持AB包以及代码热更新(?)。
2 条评论
你好,我在创建大厅成功后,调用SteamMatchmaking.RequestLobbyList的回调中 获取不到大厅数据(获取到的大厅数量为0),这是为什么呢?另外,我把appID设置为480,直接调用SteamMatchmaking.RequestLobbyList,也获取不到任何大厅数据
正常创建成功后,你的Steam状态就会更改成远程同乐在线,你可以用这个作为是否创建成功的标准。