PubSubLib.Router
1.2.0
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package PubSubLib.Router --version 1.2.0
NuGet\Install-Package PubSubLib.Router -Version 1.2.0
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="PubSubLib.Router" Version="1.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PubSubLib.Router" Version="1.2.0" />
<PackageReference Include="PubSubLib.Router" />
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 PubSubLib.Router --version 1.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: PubSubLib.Router, 1.2.0"
#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 PubSubLib.Router@1.2.0
#: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=PubSubLib.Router&version=1.2.0
#tool nuget:?package=PubSubLib.Router&version=1.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
SubPubC
Thư viện Spatial Pub/Sub cho game server viết bằng .NET. Theo dõi thực thể (Unit) trên lưới 2D và thông báo cho người quan sát (Watcher) khi unit vào/ra/di chuyển/phát sự kiện trong bán kính quan sát.
Kiến trúc 3 thành phần
┌──────────────────┐ ┌──────────────────┐ NATS ┌──────────────────┐
│ Game Client │ TCP (MyConnection) │ Router │ ◄── PubSub.Cmd ── │ PubSub Server │
│ │ ◄─────────────────► │ │ ─── PubSub.Evt ──► │ │
│ PubSubLib.Client │ │ PubSubLib.Router │ │ PubSubLib │
└──────────────────┘ └──────────────────┘ └──────────────────┘
| Thành phần | Package | Vai trò |
|---|---|---|
| Server | PubSubLib |
Sở hữu lưới không gian chính thống (authoritative). Tạo/di chuyển/hủy unit, quản lý watcher. |
| Router | PubSubLib.Router |
Cầu nối giữa game client và PubSub server. Map connection → watcherId, forward command lên NATS, demux event xuống từng client. |
| Client | PubSubLib.Client |
Chạy trong Unity/game process. Ping định kỳ để đồng bộ trạng thái, nhận event từ server để tạo/hủy GameObject. |
Quick Start
1. Dùng standalone (không module, không Natify)
Dùng PubSubLib trực tiếp trong cùng một process. Phù hợp cho local test hoặc server monolithic.
using PubSubLib;
// Tạo PubSub instance
var pubSub = IPubSub.Create(new PubSubConfig
{
GridSize = 100f // mỗi cell lưới 100x100 đơn vị
});
// Đăng ký callback — batch enter (unit vừa vào tầm quan sát)
pubSub.OnUnitEnter(tuple =>
{
var watcherIds = tuple.Item1; // List<long> — watcher nào được thông báo
var unit = tuple.Item2; // IUnit
Console.WriteLine($"[BatchEnter] Unit {unit.Id} vào tầm của watcher [{string.Join(",", watcherIds)}]");
});
// Sync enter — danh sách toàn bộ unit trong tầm khi thêm watcher hoặc re-sync
pubSub.OnUnitEnter(tuple =>
{
foreach (var u in tuple.Item2) // List<IUnit>
Console.WriteLine($"[SyncEnter] Watcher {tuple.Item1} thấy unit {u.Id}");
});
// Sync leave — unit không còn trong tầm
pubSub.OnUnitLeave(tuple =>
{
foreach (var k in tuple.Item2) // List<UnitKey>
Console.WriteLine($"[SyncLeave] Watcher {tuple.Item1} mất unit [{k.Id}]");
});
// Unit event
pubSub.OnUnitEvent(tuple =>
{
var reliable = tuple.Item5;
Console.WriteLine($"[Event] {tuple.Item2.Type}:{tuple.Item2.Id} phát '{tuple.Item3}' reliable={reliable}");
});
// Thêm watcher
pubSub.AddWatcher(watcherId: 1, position: V(0, 0), radius: 200f);
// Tạo unit async
var target = new MyGameObject();
var unit = await pubSub.CreateUnitAsync<MyGameObject>(
id: 42, type: "hero", position: V(50, 50), target: target
);
// Di chuyển unit
unit.Position = V(150, 150);
await pubSub.FlushAsync(); // đợi worker xử lý xong
// Phát sự kiện (TCP — reliable=true mặc định)
unit.PublishEvent("attack", new { damage = 50 });
// Phát sự kiện qua UDP (reliable=false)
unit.PublishEvent("bullet_fx", new { whoosh = 1 }, reliable: false);
await pubSub.FlushAsync();
// Hủy unit
unit.Destroy();
await pubSub.FlushAsync();
// Ping giữ watcher sống + đồng bộ trạng thái
pubSub.WatcherPingUnits(1, new Dictionary<string, Dictionary<long, int>>());
// Dọn dẹp
pubSub.Dispose();
static Vector2 V(float x, float y) => new Vector2 { x = x, y = y };
2. Dùng full stack (Client + Router + Server + Natify)
Dùng cả 3 package để phân tán qua mạng. Cần NATS server chạy ở nats://localhost:4222.
Server
using Natify;
using PubSubLib;
// Kết nối NATS
var natifyClient = new NatifyClientFast("nats://localhost:4222",
"PubSubServer", "ServerGroup", "VN", "Router");
// Tạo PubSub + gắn Natify
var pubSub = IPubSub.Create(new PubSubConfig { GridSize = 100f });
pubSub.AddNatify(natifyClient);
// Từ đây mọi event (BatchEnter, SyncEnter, UnitEvent...) tự động publish lên NATS PubSub.Evt
// Mọi command từ client gửi lên PubSub.Cmd được tự động xử lý
Router
using MyConnection;
using Natify;
using PubSubLib.Router;
// Tạo MyConnection server (TCP cho client, NATS cho server)
var server = IServer.Create(new ServerConfig
{
tcpPort = 9090,
udpPort = 9091,
jwtSecret = "your-secret-key",
jwtAudience = "game-audience",
jwtIssuer = "game-issuer"
});
// Xác thực user
server.OnLogin<LoginBody>(body =>
{
return Task.FromResult<IUser>(new GameUser(body.UserId));
});
// NATS bridge
var natifyServer = new NatifyServer("nats://localhost:4222",
"Router", "RouterGroup", "PubSubServer");
// Gắn router module — map connection ↔ watcherId
server.AddModule(IPubSubRouterModule.Create(natifyServer, "VN"));
Luồng Router:
- Khi client connect → Router gửi
AddWatcherlên Server qua NATS (watcherId =connection.User.Id) - Khi client disconnect → Router gửi
RemoveWatcher - Khi client gửi
PubSub.Cmd(MoveWatcher, PingUnits, PublishEvent) qua UDP → Router gánwatcherId, forward lên NATS - Khi nhận
PubSub.Evttừ NATS → Router demux đến đúng client TCP dựa trênwatcherId
Client (Unity / Game Client)
using MyConnection;
using PubSubLib.Client;
// Kết nối đến Router
var client = IClient.Create(new ClientConfig
{
tcpServer = "127.0.0.1:9090",
udpServer = "127.0.0.1:9091",
udpPingIntervalMs = 5000,
udpPingTimeoutMs = 15000
});
// Tạo PubSub client module
var pubSubModule = IPubSubClientModule.Create(new Config
{
PingIntervalMs = 1000 // ping mỗi 1 giây
});
// Đăng ký Provider — factory tạo/hủy GameObject cho từng UnitType
pubSubModule.Get()
.AddProvider(new HeroProvider())
.AddProvider(new MobProvider());
client.AddModule(pubSubModule);
// Login (UserId sẽ làm watcherId)
await client.Login(() => new LoginBody { UserId = "player_1" });
await client.ConnectServer();
// === Game loop ===
// Mỗi frame, gọi Tick() để client ping định kỳ:
// pubSubModule.Get().Tick();
//
// Khi nhân vật di chuyển, gọi MoveWatcher():
// pubSubModule.Get().MoveWatcher(newPosition, radius);
// Provider mẫu
public class HeroProvider : IProvider
{
public string UnitType => "hero";
public GameObjectTest CreateObject(long unitId, int version, byte[] data)
{
// Tạo GameObject từ prefab, áp dụng data...
var go = new GameObjectTest();
Console.WriteLine($"[Client] Tạo hero {unitId} v{version}");
return go;
}
public void DestroyObject(long unitId, GameObjectTest obj)
{
// Hủy GameObject
Console.WriteLine($"[Client] Hủy hero {unitId}");
}
public void OnEvent(long unitId, GameObjectTest obj, string eventName, byte[] data, EventMeta meta)
{
if (meta.Transport == EventTransport.Udp)
{
// Xử lý event UDP (best-effort)
}
else
{
// Xử lý event TCP (reliable)
}
}
}
Luồng Client:
Tick()định kỳ buildPingUnitsCmdchứa tất cả unit client đang track + version → gửi UDPPubSub.Cmd- Server so sánh version → trả về
SyncEnter(unit mới/thay đổi) hoặcSyncLeave(unit đã mất) - Client nhận
PubSub.Evtqua TCP →HandleBatchEnter/HandleSyncEnter/HandleBatchLeave/HandleSyncLeave - Provider
CreateObject/DestroyObjectđược gọi để tạo/hủy GameObject tương ứng - Unit track bằng
WeakReference— nếu GameObject bị GC collect, unit tự xóa khỏi danh sách ping
Chi tiết từng thành phần
| File | Nội dung |
|---|---|
| docs/Server.md | PubSubLib chi tiết: API, cấu hình, luồng xử lý nội bộ, standalone vs Natify |
| docs/Router.md | PubSubLib.Router chi tiết: bridge client-server, map connection, demux event |
| docs/Client.md | PubSubLib.Client chi tiết: ping cycle, IProvider, Unit tracking, WeakReference |
Cấu trúc dự án
SubPubC.sln
├── PubSubLib/ # Core library (multi-target: netstandard2.1, net9.0)
│ ├── IPubSub.cs # Public interface
│ ├── PubSub.cs # Core implementation
│ ├── IUnit.cs # Unit interface
│ ├── Unit.cs # Unit implementation (WeakReference)
│ ├── Watcher.cs # Watcher (vị trí, bán kính, known types)
│ ├── EventChannel.cs # Worker thread (Channel<Action>)
│ ├── Cell.cs # Grid cell
│ ├── PubSubNatifySync.cs # NATS bridge (inbound/outbound)
│ └── Messages/ # Protobuf definitions
│
├── PubSubLib.Client/ # Game client module (netstandard2.1, Unity IL2CPP)
│ ├── IPubSubClient.cs # Client interface (Tick, MoveWatcher, AddProvider)
│ ├── PubSubClient.cs # Client implementation
│ ├── IPubSubClientModule.cs # Module interface (IClientModule)
│ ├── PubSubClientModule.cs # Bridges MyConnection events
│ ├── IProvider.cs # Factory tạo/hủy GameObject, OnEvent
│ ├── EventMeta.cs # EventTransport enum (Tcp/Udp)
│ └── Config.cs # PingIntervalMs
│
├── PubSubLib.Router/ # Router module (netstandard2.1)
│ ├── IPubSubNatifyClient.cs # Natify client interface
│ ├── PubSubNatifyClient.cs # NATS communication
│ ├── IPubSubRouterModule.cs # Router module interface (IServerModule)
│ └── PubSubRouterModule.cs # Maps connections ↔ watchers
│
├── PubSubLib.Contracts/ # Shared protobuf messages
├── PubSubLibTest/ # Test project (xUnit)
└── SubPubCTest/ # ASP.NET Core test app
NuGet
<PackageReference Include="PubSubLib" Version="1.1.0" />
<PackageReference Include="PubSubLib.Client" Version="1.1.0" />
<PackageReference Include="PubSubLib.Router" Version="1.1.0" />
<PackageReference Include="PubSubLib.Contracts" Version="1.1.0" />
Build & Test
# Build
dotnet build PubSubLib/PubSubLib.csproj
dotnet build PubSubLibTest/PubSubLibTest.csproj
# Test (cần NATS server cho test Natify)
dotnet test PubSubLibTest/PubSubLibTest.csproj
Docker
docker-compose up -d # NATS + SubPubC console
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.1
- MyConnection (>= 1.0.4)
- Natify (>= 1.0.2)
- PubSubLib (>= 1.2.0)
- System.Threading.Channels (>= 10.0.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.