T2FGame.Room 1.0.9

dotnet add package T2FGame.Room --version 1.0.9
                    
NuGet\Install-Package T2FGame.Room -Version 1.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="T2FGame.Room" Version="1.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="T2FGame.Room" Version="1.0.9" />
                    
Directory.Packages.props
<PackageReference Include="T2FGame.Room" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add T2FGame.Room --version 1.0.9
                    
#r "nuget: T2FGame.Room, 1.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package T2FGame.Room@1.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=T2FGame.Room&version=1.0.9
                    
Install as a Cake Addin
#tool nuget:?package=T2FGame.Room&version=1.0.9
                    
Install as a Cake Tool

T2FGame.Room

T2FGame 框架的房间模块,提供类似 ioGame 的游戏房间管理功能。

功能特性

  • 房间管理:创建、加入、离开、解散房间
  • 玩家管理:房间内玩家状态管理
  • 房间广播:向房间内所有/部分玩家发送消息
  • 匹配系统:支持快速匹配和自定义匹配
  • 房间状态机:等待、游戏中、结算等状态流转

安装

<PackageReference Include="T2FGame.Room" />

核心概念

房间生命周期

Created → Waiting → Playing → Settling → Closed
   │         │                              ▲
   │         │         (游戏结束)            │
   │         └──────────────────────────────┘
   │                   (所有人离开)
   └───────────────────────────────────────────→

快速开始

1. 定义房间类型

public class BattleRoom : GameRoom<BattleRoomPlayer>
{
    public int MaxRounds { get; set; } = 3;
    public int CurrentRound { get; private set; }

    protected override void OnPlayerJoin(BattleRoomPlayer player)
    {
        // 玩家加入房间时的逻辑
        BroadcastToAll(new PlayerJoinNotify { PlayerId = player.PlayerId });
    }

    protected override void OnPlayerLeave(BattleRoomPlayer player)
    {
        // 玩家离开房间时的逻辑
        BroadcastToAll(new PlayerLeaveNotify { PlayerId = player.PlayerId });
    }

    public void StartGame()
    {
        if (State != RoomState.Waiting) return;
        if (PlayerCount < MinPlayers) return;

        State = RoomState.Playing;
        CurrentRound = 1;
        BroadcastToAll(new GameStartNotify { Round = CurrentRound });
    }
}

public class BattleRoomPlayer : RoomPlayer
{
    public int Score { get; set; }
    public bool IsReady { get; set; }
    public int TeamId { get; set; }
}

2. 配置房间服务

services.AddT2FGameRoom(options =>
{
    options.MaxRoomsPerServer = 1000;
    options.DefaultMaxPlayers = 4;
    options.RoomIdleTimeout = TimeSpan.FromMinutes(30);
});

// 注册房间类型
services.AddRoomType<BattleRoom, BattleRoomPlayer>("battle");
services.AddRoomType<LobbyRoom, LobbyPlayer>("lobby");

核心组件

GameRoom(游戏房间)

public abstract class GameRoom<TPlayer> where TPlayer : RoomPlayer
{
    // 基本属性
    public string RoomId { get; }
    public string RoomType { get; }
    public RoomState State { get; protected set; }
    public long OwnerId { get; protected set; }

    // 容量设置
    public int MaxPlayers { get; set; }
    public int MinPlayers { get; set; }
    public int PlayerCount { get; }
    public bool IsFull { get; }

    // 玩家管理
    public TPlayer? GetPlayer(long playerId);
    public IReadOnlyList<TPlayer> GetAllPlayers();
    public bool HasPlayer(long playerId);

    // 加入/离开
    public virtual Result Join(TPlayer player);
    public virtual Result Leave(long playerId);

    // 广播
    public void BroadcastToAll(IMessage message);
    public void BroadcastToOthers(long excludePlayerId, IMessage message);
    public void BroadcastToTeam(int teamId, IMessage message);
    public void SendToPlayer(long playerId, IMessage message);

    // 生命周期钩子
    protected virtual void OnPlayerJoin(TPlayer player) { }
    protected virtual void OnPlayerLeave(TPlayer player) { }
    protected virtual void OnRoomClose() { }
}

RoomPlayer(房间玩家)

public class RoomPlayer
{
    public long PlayerId { get; set; }
    public string Nickname { get; set; }
    public int Seat { get; set; }
    public PlayerState State { get; set; }
    public DateTime JoinTime { get; set; }

    // 自定义数据
    public Dictionary<string, object> Properties { get; }
}

public enum PlayerState
{
    Idle,       // 空闲
    Ready,      // 准备
    Playing,    // 游戏中
    Offline     // 离线
}

RoomManager(房间管理器)

public interface IRoomManager
{
    // 创建房间
    Task<Result<TRoom>> CreateRoomAsync<TRoom, TPlayer>(
        long ownerId,
        Action<TRoom>? configure = null)
        where TRoom : GameRoom<TPlayer>, new()
        where TPlayer : RoomPlayer;

    // 获取房间
    Task<GameRoom<TPlayer>?> GetRoomAsync<TPlayer>(string roomId)
        where TPlayer : RoomPlayer;

    // 查找玩家所在房间
    Task<string?> GetPlayerRoomIdAsync(long playerId);

    // 加入房间
    Task<Result> JoinRoomAsync<TPlayer>(
        string roomId,
        TPlayer player)
        where TPlayer : RoomPlayer;

    // 离开房间
    Task<Result> LeaveRoomAsync(string roomId, long playerId);

    // 解散房间
    Task<Result> DisbandRoomAsync(string roomId, long operatorId);

    // 查询房间列表
    Task<IReadOnlyList<RoomInfo>> GetRoomListAsync(
        string roomType,
        RoomQueryFilter? filter = null);
}

房间 Action

[ActionController(cmd: CmdModule.Room)]
public class RoomController
{
    private readonly IRoomManager _roomManager;

    [ActionMethod(subCmd: RoomCmd.Create)]
    public async Task<CreateRoomResponse> CreateRoom(
        CreateRoomRequest request,
        FlowContext context)
    {
        var result = await _roomManager.CreateRoomAsync<BattleRoom, BattleRoomPlayer>(
            context.UserId,
            room =>
            {
                room.MaxPlayers = request.MaxPlayers;
                room.RoomName = request.RoomName;
            });

        return result.Match(
            room => new CreateRoomResponse { RoomId = room.RoomId },
            error => throw new GameException(error));
    }

    [ActionMethod(subCmd: RoomCmd.Join)]
    public async Task<JoinRoomResponse> JoinRoom(
        JoinRoomRequest request,
        FlowContext context)
    {
        var player = new BattleRoomPlayer
        {
            PlayerId = context.UserId,
            Nickname = request.Nickname
        };

        var result = await _roomManager.JoinRoomAsync(request.RoomId, player);

        return result.Match(
            _ => new JoinRoomResponse { Success = true },
            error => new JoinRoomResponse { ErrorCode = error.Code });
    }

    [ActionMethod(subCmd: RoomCmd.Leave)]
    public async Task<LeaveRoomResponse> LeaveRoom(FlowContext context)
    {
        var roomId = await _roomManager.GetPlayerRoomIdAsync(context.UserId);
        if (roomId == null)
            return new LeaveRoomResponse { ErrorCode = "NotInRoom" };

        await _roomManager.LeaveRoomAsync(roomId, context.UserId);
        return new LeaveRoomResponse { Success = true };
    }
}

匹配系统

匹配请求

[ActionMethod(subCmd: RoomCmd.QuickMatch)]
public async Task<MatchResponse> QuickMatch(
    MatchRequest request,
    FlowContext context)
{
    var result = await _matchService.RequestMatchAsync(new MatchTicket
    {
        PlayerId = context.UserId,
        RoomType = request.RoomType,
        MatchMode = request.MatchMode,
        Rating = request.Rating,
        Preferences = request.Preferences
    });

    return new MatchResponse { TicketId = result.TicketId };
}

匹配结果通知

// 匹配成功后推送给所有匹配到的玩家
await BroadcastToPlayers(matchedPlayerIds, new MatchSuccessNotify
{
    RoomId = room.RoomId,
    Players = matchedPlayers.Select(p => p.ToProto())
});

房间状态

public enum RoomState
{
    Created,    // 已创建
    Waiting,    // 等待中
    Starting,   // 启动中
    Playing,    // 游戏中
    Paused,     // 暂停
    Settling,   // 结算中
    Closed      // 已关闭
}

房间事件

// 房间事件定义
public record RoomCreatedEvent(string RoomId, string RoomType, long OwnerId) : IDomainEvent;
public record PlayerJoinedRoomEvent(string RoomId, long PlayerId) : IDomainEvent;
public record PlayerLeftRoomEvent(string RoomId, long PlayerId) : IDomainEvent;
public record RoomStateChangedEvent(string RoomId, RoomState OldState, RoomState NewState) : IDomainEvent;
public record RoomClosedEvent(string RoomId) : IDomainEvent;

// 事件处理器
public class RoomEventHandler :
    IEventHandler<PlayerJoinedRoomEvent>,
    IEventHandler<PlayerLeftRoomEvent>
{
    public async Task HandleAsync(PlayerJoinedRoomEvent @event, CancellationToken ct)
    {
        // 记录日志、更新统计等
    }

    public async Task HandleAsync(PlayerLeftRoomEvent @event, CancellationToken ct)
    {
        // 检查房间是否需要关闭等
    }
}

目录结构

T2FGame.Room/
├── Configuration/
│   └── RoomOptions.cs           # 房间配置
├── Core/
│   ├── GameRoom.cs              # 房间基类
│   ├── RoomPlayer.cs            # 房间玩家
│   ├── RoomState.cs             # 房间状态
│   └── RoomInfo.cs              # 房间信息
├── Management/
│   ├── IRoomManager.cs          # 房间管理接口
│   ├── RoomManager.cs           # 房间管理实现
│   └── RoomRegistry.cs          # 房间注册表
├── Matching/
│   ├── IMatchService.cs         # 匹配服务接口
│   ├── MatchService.cs          # 匹配服务实现
│   └── MatchTicket.cs           # 匹配票据
├── Events/
│   └── RoomEvents.cs            # 房间事件定义
└── Extensions/
    └── ServiceCollectionExtensions.cs # 服务注册

最佳实践

  1. 房间 ID 生成:使用有意义的前缀 + UUID,便于调试
  2. 玩家状态同步:使用增量更新而非全量同步
  3. 掉线重连:保留玩家位置一段时间,支持重连
  4. 房间清理:定期清理空闲房间,释放资源
  5. 并发控制:房间内操作使用锁或队列保证顺序
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on T2FGame.Room:

Package Downloads
T2FGame

T2FGame Framework - A high-performance distributed game server framework inspired by ioGame. This meta-package includes all T2FGame components.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.9 442 12/11/2025
1.0.8 439 12/11/2025
1.0.7 437 12/11/2025
1.0.6 437 12/11/2025
1.0.5 463 12/10/2025
1.0.4 448 12/10/2025
1.0.3 467 12/9/2025
1.0.2 369 12/8/2025
1.0.1 507 12/1/2025
1.0.0 187 11/28/2025
0.0.1 376 12/8/2025