Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@

- [Overview](#overview)
- [Core Capabilities](#core-capabilities)
- [Multi-World Architecture Comparison](#architecture-tradeoffs)
- [Version Matrix](#version-matrix)
- [Architecture](#architecture)
- [Runtime Architecture](#architecture)
- [Quick Start](#quick-start)
- [Launcher Reference](#launcher-reference)
- [Publisher Reference](#publisher-reference)
Expand All @@ -58,7 +59,7 @@ Compared with approaches that push this coordination outside process boundaries,
This shared listener-and-coordination model reduces the extra overhead and complexity introduced by cross-process relays, making cross-world interaction, data interchange, and unified operations easier while still leaving enough routing control to define the default join target and take over later world-switch flows.

From the player's side, this still behaves like a normal Terraria entry point: clients connect to one shared listener port, and `UnifiedServerCoordinator` routes each connection to the selected world inside the same process. If you push this model further, you can build more gameplay-driven setups: fully connected multi-instance world clusters, elastic worlds that load or unload region-sized shards on demand, or private worlds tuned per player for logic and resource budgets.
These are reachable directions, even though the launcher does not currently ship them as default out-of-the-box features, and heavier implementations like these may stay out of the launcher core itself; you can still expect usable example plugins to land under `plugins/` over time.
These are reachable directions, even though the launcher does not currently ship them as default out-of-the-box features, you can still expect usable example plugins to land under `plugins/` over time.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Consider fixing the comma splice by splitting into two sentences or using a semicolon.

This sentence currently joins two independent clauses with only a comma, which is a comma splice. Consider either using a semicolon ("…features; you can still expect…") or splitting into two sentences ("…features. You can still expect…").

Suggested change
These are reachable directions, even though the launcher does not currently ship them as default out-of-the-box features, you can still expect usable example plugins to land under `plugins/` over time.
These are reachable directions, even though the launcher does not currently ship them as default out-of-the-box features; you can still expect usable example plugins to land under `plugins/` over time.


---

Expand All @@ -79,6 +80,55 @@ These are reachable directions, even though the launcher does not currently ship

---

<a id="architecture-tradeoffs"></a>
## ⚖️ Multi-World Architecture Comparison

> Here, `proxy-based` broadly refers to the common family of designs built around a front proxy, multiple independent backend server processes, packet-level relays or rewriting, and optional shared storage or control-plane components.

<details>
<summary><strong>Deployment and Lifecycle</strong></summary>

| Dimension | UnifierTSL (single-process unified coordination) | Proxy-based (front proxy + multiple backend processes) | Stronger Fit |
|:--|:--|:--|:--|
| Failure isolation | Worlds share one host process; isolation between contexts exists at the thread/runtime-context level | Process-level isolation; one backend crash usually does not directly take down other backends or the proxy itself | Proxy-based |
| Instance-level restart | World contexts can be started and stopped freely | A single backend can be restarted, replaced, or moved while the front entry point stays up | Depends on the operational goal |
| Plugin hot reload | The runtime provides standard support; whether a plugin can hot reload depends on the plugin's own design, and players are usually unaffected | Backend plugins can be reloaded cleanly by restarting only the target backend instance, though that may require moving players to a temporary backend | Depends on the operational goal |
| Horizontal elasticity | The core design targets multi-world coordination inside one host; instances can be created freely, but they still share one process resource pool | Naturally suited to cross-machine, cross-container, or cross-device scale-out | Proxy-based |
| Existing plugin ecosystem reuse | Requires adaptation to the Unifier runtime model | Directly uses the existing plugin ecosystem | Proxy-based |

</details>

<details>
<summary><strong>Runtime Coordination and Transfer</strong></summary>

| Dimension | UnifierTSL (single-process unified coordination) | Proxy-based (front proxy + multiple backend processes) | Stronger Fit |
|:--|:--|:--|:--|
| World customizability | World contexts are fully customizable and can be changed dynamically at runtime | Depends on the backend implementation; in practice, most setups are relatively static after startup | UnifierTSL |
| Server-side consistency | World existence, routing targets, and connection ownership are resolved directly inside one runtime, so the consistency surface is narrower | Depends on cross-process topology, registration, shared storage, or an external control plane, so the race surface is wider | UnifierTSL |
| State awareness and switch orchestration | One coordinator can see source world, target world, and player connection state together, so fallback and recovery logic can be centralized | Target readiness, transfer failures, disconnect recovery, and rollback may require cross-process coordination | UnifierTSL |
| Data transfer and entity migration | Temporary state, plugin-attached data, and runtime objects can be transferred or coordinated directly inside one runtime | State often has to be serialized, protocolized, or moved through shared databases or custom packets first | UnifierTSL |
| Connection-state maintenance | One listener keeps ownership of the client connection throughout world switches | The proxy must maintain both client-side and backend-side connections and recover from failures on either side | UnifierTSL |
| Cross-world plugin interoperability | Feels more like “one plugin working across many `ServerContext` instances,” with direct reuse of in-process events and APIs | Feels more like distributed-systems work, usually requiring message protocols, shared storage, or sync layers first | UnifierTSL |

</details>

<details>
<summary><strong>Operations and System Shape</strong></summary>

| Dimension | UnifierTSL (single-process unified coordination) | Proxy-based (front proxy + multiple backend processes) | Stronger Fit |
|:--|:--|:--|:--|
| Unified management cost | Entry point, world lifecycle, default join policy, and config application all live on one coordination plane | Management is usually split across the proxy, backend instances, and external orchestration pieces | UnifierTSL |
| Monitoring and observability | Logs, status bars, event flow, and per-world runtime metrics aggregate naturally | Observability is often split across proxy, backend, and external control layers, so correlation costs more | UnifierTSL |
| Debugging and incident handling | A single process gives you a more continuous timeline for debugging, log correlation, and reproduction | Failures can be spread across proxy, backend, shared storage, and deployment orchestration layers | UnifierTSL |
| Network and serialization overhead | Critical coordination paths can stay in-process and avoid extra hops or auxiliary protocols | Player transfers and extended state propagation may introduce extra packets plus related interception strategies, or rely on side channels | UnifierTSL |
| Single-node capability density | A single host can already cover routing, coordination, linkage, plugin interoperability, and unified operations | A single node is more of a routing shell, with heavier behavior often shifted toward backends or external systems | UnifierTSL |

</details>

It is important to note that UnifierTSL and proxy-based topologies are not mutually exclusive. Because UnifierTSL already organizes many worlds behind a single external listener, it can still sit behind a higher-level gateway or proxy as a stronger single-node backend. In the end, the better choice depends on your needs: proxy-based stacks have a higher ceiling for cross-device, cross-process scaling and isolation, so if you prefer elastic multi-machine deployment with basic cross-server features, proxy-based is likely the better fit. By contrast, UnifierTSL has more natural advantages in single-node multi-world consistency, migration, and coordination. If you want to build a more structured and interactive multi-world group, UnifierTSL is likely the more interesting option to try today.

---

<a id="version-matrix"></a>
## 📊 Version Matrix

Expand All @@ -88,7 +138,7 @@ The baseline values below come straight from project files and restored package
| Component | Version | Source |
|:--|:--|:--|
| Target framework | `.NET 9.0` | `src/UnifierTSL/*.csproj` |
| Terraria | `1.4.5.6` | restored `OTAPI.dll` resolved via `src/UnifierTSL/obj/project.assets.json` (assembly file version) |
| Terraria | `1.4.5.6` | `OTAPI.dll` from the OTAPI USP package referenced by this project |
| OTAPI USP | `1.1.0-pre-release-upstream.30` | `src/UnifierTSL/UnifierTSL.csproj` |

<details>
Expand Down Expand Up @@ -117,7 +167,7 @@ Additional dependency baselines:
---

<a id="architecture"></a>
## 🏗 Architecture
## 🏗 Runtime Architecture

<p align="center">
<img src="./docs/assets/readme/arch-flow.svg" alt="Architecture flow" width="100%">
Expand Down
59 changes: 55 additions & 4 deletions docs/README.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@

- [概览](#overview)
- [核心能力](#core-capabilities)
- [多世界架构横向比对](#architecture-tradeoffs)
- [版本矩阵](#version-matrix)
- [架构](#architecture)
- [运行架构](#architecture)
- [快速开始](#quick-start)
- [启动器参考](#launcher-reference)
- [Publisher 参考](#publisher-reference)
Expand All @@ -58,7 +59,7 @@ UnifierTSL 把 [OTAPI Unified Server Process](https://github.com/CedaryCat/OTAPI
这种共享监听入口与协调平面的方式,减少了跨进程中转带来的额外开销与复杂度,既方便建立跨世界联动、数据互通和统一运维,也保留了足够的路由控制空间,用于定义默认入服目标并接管后续的世界切换流程。

从玩家视角看,它依然像一个普通的 Terraria 服务器入口:客户端只需要连到同一个监听端口,随后由 `UnifiedServerCoordinator` 在同一进程内把连接路由到目标世界;如果继续把这套模型往前推,你可以做出更偏玩法的形态:完全互通的多实例世界集群、按需加载/卸载区域分片的弹性世界,或为单个玩家定制逻辑和资源预算的私人世界。
这些是可达方向,尽管启动器目前并未直接提供这些开箱即用的默认能力;而这类较重实现也未必会放进启动器核心本体,但你仍可以期待后续在 `plugins/` 下逐步补上的可用示例插件。
这些是可达方向,尽管启动器目前并未直接提供这些开箱即用的默认能力,但你仍可以期待后续在 `plugins/` 下逐步补上的可用示例插件。

---

Expand All @@ -79,6 +80,56 @@ UnifierTSL 把 [OTAPI Unified Server Process](https://github.com/CedaryCat/OTAPI

---

<a id="architecture-tradeoffs"></a>
## ⚖️ 多世界架构横向比对

> 这里的 `proxy-based` 泛指“前置代理 + 多个后端独立服务器进程 + 协议级转发/改写 + 可选共享存储或控制面”的常见可能形态。

<details>
<summary><strong>部署与生命周期</strong></summary>

| 维度 | UnifierTSL(同进程统一协调) | proxy-based(前置代理 + 多后端进程) | 更占优 |
|:--|:--|:--|:--|
| 错误域隔离 | 多世界共享宿主进程;上下文之间有线程级隔离 | 进程级隔离,单个后端崩溃通常不会直接拖垮其他后端或代理本身 | proxy-based |
| 实例级重启 | 支持世界上下文自由启停 | 可单独重启、替换、迁移某个后端实例,外层入口可继续存活 | 视具体需求而定 |
| 插件热重载 | 运行时提供标准支持,由插件自身设计决定是否可热重载,通常玩家端无感 | 可单独重启后端实例完成后端插件干净重载,可能需要迁移玩家到临时后端 | 视具体需求而定 |
| 水平弹性部署 | 核心设计目标为单宿主内多世界协调,可任意创建实例,但共享同一进程资源 | 天然适合跨设备、跨容器、跨主机扩展 | proxy-based |
| 现有插件生态复用 | 需要按 Unifier 运行时模型适配 | 直接使用当前插件生态 | proxy-based |

</details>

<details>
<summary><strong>运行时协同与迁移</strong></summary>

| 维度 | UnifierTSL(同进程统一协调) | proxy-based(前置代理 + 多后端进程) | 更占优 |
|:--|:--|:--|:--|
| 世界定制化 | 完全可定制并可在运行中动态更改的世界上下文 | 视具体后端实现而定,通常启动后不再变动 | UnifierTSL |
| 服务器一致性 | 世界存在性、路由目标、连接归属都在同一运行时里直接判定,一致性面更窄 | 依赖跨进程拓扑、注册信息、共享存储或控制面,竞态面更宽 | UnifierTSL |
| 感知与切换编排 | 同一协调器可同时感知来源世界、目标世界与玩家连接状态,回退与兜底可集中处理 | 可能需要跨进程协同处理目标就绪、切换失败、掉线恢复和回滚 | UnifierTSL |
| 数据传输与实体迁移 | 临时状态、插件附加数据、运行时对象可以在统一运行时内直接转移或协调 | 往往必须先序列化、协议化,或借共享数据库 / 自定义数据包搬运 | UnifierTSL |
| 连接状态维护 | 单一监听入口持续持有客户端连接,切世界时不需要把连接所有权交给其他进程 | 代理需同时维护前后端连接,并处理任一侧掉线、重连与状态复原 | UnifierTSL |
| 插件跨服互操作 | 更像“同一插件面对多个 `ServerContext`”,跨服协作可以直接复用进程内事件与 API | 更像分布式系统开发,通常要先定义消息协议、共享存储或同步层 | UnifierTSL |

</details>


<details>
<summary><strong>运维与系统形态</strong></summary>

| 维度 | UnifierTSL(同进程统一协调) | proxy-based(前置代理 + 多后端进程) | 更占优 |
|:--|:--|:--|:--|
| 统一管理成本 | 入口、世界生命周期、默认入服策略、配置应用都集中在同一协调平面 | 管理面通常分散在代理、后端实例和外部编排组件之间 | UnifierTSL |
| 状态监测与观测 | 日志、状态栏、事件流、各世界运行指标天然可聚合 | 观测往往分散在代理层、后端层和外部控制面,拼接成本较高 | UnifierTSL |
| 调试与故障定位 | 单进程时间线更连续,调试会话、日志关联和问题复现更集中 | 故障可能散落在代理、后端、共享存储和运维编排多个层面 | UnifierTSL |
| 网络与序列化开销 | 关键协调路径可留在进程内,避免额外 hop 和附加协议 | 玩家迁移与扩展状态传播可能引入额外数据包和相关拦截策略、或通过旁路信道实现 | UnifierTSL |
| 单节点能力密度 | 单机内即可覆盖路由、协调、联动、插件互通与统一运维 | 单节点更像路由壳层,复杂能力常转移到后端或外部系统 | UnifierTSL |

</details>

必须说明的是,UnifierTSL 与 proxy-based 并不互斥。由于 UnifierTSL 已经把多世界组织成单一对外监听入口,它完全可以作为一个更强的“单节点后端”继续挂到更外层的 gateway / proxy 前面。总之,具体的选择取决于你的需求,proxy-based 在跨设备、跨进程的伸缩与隔离问题上具备更高上限,如果你倾向于跨设备弹性部署并体验基础跨服功能,proxy-based会是你的最优选择。相比之下 UnifierTSL 可能在单节点内部的多世界一致性、迁移和协同能力方面具备天然优势,如果你想设计更具组织性和交互能力的多世界群组,也许现在就可以尝试UnifierTSL来搭建你的多世界服务器。

---

<a id="version-matrix"></a>
## 📊 版本矩阵

Expand All @@ -88,7 +139,7 @@ UnifierTSL 把 [OTAPI Unified Server Process](https://github.com/CedaryCat/OTAPI
| 组件 | 版本 | 来源 |
|:--|:--|:--|
| 目标框架 | `.NET 9.0` | `src/UnifierTSL/*.csproj` |
| Terraria | `1.4.5.6` | 通过 `src/UnifierTSL/obj/project.assets.json` 定位已还原的 `OTAPI.dll`(程序集文件版本) |
| Terraria | `1.4.5.6` | 项目引用的 OTAPI.USP 包中的 `OTAPI.dll` |
| OTAPI USP | `1.1.0-pre-release-upstream.30` | `src/UnifierTSL/UnifierTSL.csproj` |

<details>
Expand Down Expand Up @@ -117,7 +168,7 @@ UnifierTSL 把 [OTAPI Unified Server Process](https://github.com/CedaryCat/OTAPI
---

<a id="architecture"></a>
## 🏗 架构
## 🏗 运行架构

<p align="center">
<img src="./assets/readme/arch-flow.svg" alt="Architecture flow" width="100%">
Expand Down
Loading