PubSubLib 1.1.0
.NET 9.0
This package targets .NET 9.0. The package is compatible with this framework or higher.
.NET Standard 2.1
This package targets .NET Standard 2.1. The package is compatible with this framework or higher.
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 --version 1.1.0
NuGet\Install-Package PubSubLib -Version 1.1.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" Version="1.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PubSubLib" Version="1.1.0" />
<PackageReference Include="PubSubLib" />
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 --version 1.1.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: PubSubLib, 1.1.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@1.1.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&version=1.1.0
#tool nuget:?package=PubSubLib&version=1.1.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 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. |
| .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
- Google.Protobuf (>= 3.34.1)
- Natify (>= 1.0.2)
- PubSubLib.Contracts (>= 1.1.0)
-
net9.0
- Google.Protobuf (>= 3.34.1)
- Natify (>= 1.0.2)
- PubSubLib.Contracts (>= 1.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PubSubLib:
| Package | Downloads |
|---|---|
|
PubSubLib.Router
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.51.10 | 53 | 7/6/2026 |
| 1.51.8 | 95 | 7/6/2026 |
| 1.51.7 | 95 | 7/6/2026 |
| 1.51.6 | 93 | 7/6/2026 |
| 1.51.5 | 58 | 6/24/2026 |
| 1.51.4 | 63 | 6/24/2026 |
| 1.51.2 | 54 | 6/23/2026 |
| 1.51.1 | 97 | 6/23/2026 |
| 1.51.0 | 98 | 6/21/2026 |
| 1.50.0 | 57 | 6/21/2026 |
| 1.4.0 | 61 | 6/19/2026 |
| 1.3.0 | 109 | 6/19/2026 |
| 1.2.0 | 103 | 6/19/2026 |
| 1.1.0 | 102 | 6/18/2026 |
| 1.0.0 | 66 | 6/17/2026 |