条件配置同步

创作者: shudnal
已更新:2026-07-11 19:15:17
248KB

关于此 MOD

条件配置同步

条件 条件配置同步 —将可选的CCS适配器直接嵌入你的模组项目中(作为源文件或通过ILRepack),并在以下情况下自动添加配置同步: CCS 1.0.10 或更新版本 已安装在当前模组包中;没有 CCS 或使用 CCS 1.0.5-1.0.9 时,相同设置仍为普通的本地 BepInEx 配置项。

条件配置同步是《英灵神殿》模组的共享基础库。它本身不添加游戏内容、物品、界面或配置选项。当其他模组将其列为依赖项时,请安装它。

该包提供集中式配置同步、版本检查、服务端所有权与准入策略覆盖、受保护锁定以及同步运行时值。将此逻辑保留在单个独立依赖中意味着,只需更新此包即可发布修复,而无需重新构建每个使用它的模组。

这是一个独立的同步选项,面向需要按设置项配置所有权策略、隐藏设置控制以及扩展运行时值行为的模组作者。Jotunn 和 ServerSync 仍是各自独立的库,拥有各自的使用场景和开发路线。

玩家

通常,模组管理器会自动将条件配置同步作为依赖项进行安装。当任何已启用的模组依赖它时,请保持其处于安装状态。

这个包:

  • 做 不 替换、修改或拦截 服务器同步 被其他模组使用;
  • 做 不 迁移或修改属于其他模组的配置;
  • 可与Jotunn及使用以下内容的模组同时运行 服务器同步;
  • 仅处理明确针对条件配置同步构建的模组。

仅安装此包不会对游戏玩法产生任何影响。

包内物品

雷神商店包内含:

  • ConditionalConfigSync.Plugin.dll - BepInEx 引导程序已注册为 _舒德纳尔.条件配置同步;
  • ConditionalConfigSync.dll - 依赖模组所使用的公共 API 和同步运行时;
  • ConditionalConfigSync.xml - 为IDE和模组作者提供的IntelliSense文档;

两个DLL文件必须一起保留安装。XML和文档文件在运行时是可选的,但对开发、验证和重新分发很有用。

兼容性

条件配置同步使用其独立的BepInEx和Harmony标识符:

_shudnal.条件配置同步

它不会修补、替换或禁用Jotunn同步或 服务器同步. 这些库可以在同一进程中并存,因为每个模组会继续使用其编译时所针对的同步库。

嵌入或IL合并 ConditionalConfigSync.dll 嵌入到另一个模组中是不受支持的。内嵌副本会拒绝初始化并报告明确的错误。请改用独立的Thunderstore依赖项。

服务器管理员

默认行为

每个已注册的设置项都有三种归属模式之一,由该模组的作者选择:

  • 始终由服务器控制 - 始终从服务器同步,且无法通过策略释放。Mod作者应将其用于共享机制和同步状态,这些机制和状态必须在服务器和每个客户端上使用相同的有效值。典型示例包括游戏规则、世界状态生成、共享事件、网络可见计算,以及当对等端不一致时会出现故障的功能开关;
  • 条件 - 使用模组定义的服务器/客户端默认值,并可能被服务器策略覆盖。当管理员可以在单一共享服务器值和各客户端行为之间做出合理选择时,此选项适用;
  • 始终客户端控制 始终是每个客户端的本地设置,无法通过同步策略强制应用。它用于展示、本地界面、控制以及其他不参与共享机制的行为。

一个模组还可以注册一个锁定设置,用于控制普通客户端是否可以发布对服务器控制设置的更改。隐藏状态策略是独立的,并且可以在任何所有权模式下对兼容的配置管理器隐藏设置。模组作者还可以将其远程安装要求选择加入 条件性,允许服务器要求或允许没有该特定模组的客户端,同时保留作者声明的默认值。

政策文件创建于 BepInEx/配置/shudnal.条件配置同步 在服务器上。现有文件在服务器启动期间、使用文件监视器之前被同步读取。读取会重试直到文件元数据稳定,因此常见的编辑器保存模式(如截断/写入/重命名)不会用部分快照替换正在生效的策略。随后这些文件会被监视变化,并可在服务器运行期间进行编辑。

锁定行为

条件配置同步提供了一种ServerSync用户熟悉的锁定模型,并为锁定设置本身增加了显式保护。

启用锁定后:

  • 普通客户端无法发布对服务器控制设置的更改;
  • 服务器管理员获得豁免,可以编辑它们;
  • 客户端控制的设置保持本地可编辑。

当锁定被禁用时,普通客户端只有在模组作者明确启用了未锁定客户端更新时,才能发布对服务器控制设置的更改。此选项默认禁用;无论该选项如何,管理员始终有权进行操作。

锁定设置始终受到保护:

  • 它始终由服务器控制;
  • 无法通过策略强制交由客户端控制;
  • 非管理员客户端即使在配置其余部分解锁的情况下也无法更改它。

这会阻止客户端通过先更改锁定设置来试图为自己授予权限。

客户端只读元数据仅作为用户界面辅助。CCS还会在运行时保护已注册的BepInEx值,并在服务器上独立验证每一次客户端更新。被接受的客户端值由服务器应用并规范化,然后通过服务器重新构建的数据包分发。原始客户端数据包绝不会转发给其他客户端。被拒绝的更新会在发送者仍处于连接状态时收到权威修正。

同步策略

文件:

BepInEx/config/shudnal.ConditionalConfigSync/ConditionalConfigSync.SyncPolicy.cfg

规则可以针对一个确切设置或整个配置部分:

ModGuid.Section.Key ModGuid.Section

使用 + 强制获取服务器所有权并 - 强制客户端归属:

# 精确设置 + author.mod.General.伤害倍率 - author.mod.Interface.显示状态面板 # 每个区域中的条件设置 + author.mod.Gameplay - author.mod.Interface

规则:

  • + 标识符 部队匹配 有条件的 设置由服务器控制;
  • - 标识符 兵力匹配 条件 设置由客户端控制;
  • 精确设置规则优先于整节规则;
  • 没有匹配的条目保留模组作者的默认设置;
  • 始终由服务器控制 和 始终客户端控制 忽略同步策略的所有权覆盖;
  • 格式错误、重复、冲突、未知和忽略的条目可以通过以下方式报告: 条件配置同步策略验证;
  • 将受保护的锁定设置强制设为客户端控制的操作将被忽略。

策略通常通过这些文件进行编辑。兼容的配置界面可以使用公共API,让经过身份验证的服务器管理员切换单个 条件 在服务器控制和客户端控制的所有权之间进行设置。服务器将该操作持久化为精确设置规则,或者当请求的所有权已由模组默认值或节规则提供时,移除该精确规则。控制台命令有意提供重载、验证、状态和转储操作,但不会添加、移除或重写规则。

典型用途:

  • 在公共服务器上强制执行原本仅限客户端的游戏选项;
  • 从服务器控制中释放外观或界面设置;
  • 切换整个部分,无需逐一列出每项设置;
  • 覆盖一项设置,使其与所在区块的其余设置不同;
  • 暂时测试另一种归属模型,无需重建模组。

模组要求政策

文件:

BepInEx/config/shudnal.ConditionalConfigSync/ConditionalConfigSync.ModRequirements.cfg

此策略控制以下模组的连接准入:其作者明确使用 条件模式它与配置所有权分离,不是通用的客户端模组列表允许/拒绝机制。

使用 + 要求连接客户端必须安装此模组,并且 - 为了让没有它的客户端也能使用:

# 即使作者默认设置为可选,也要求此模组 + author.mod # 即使作者默认设置为必需,也允许没有此模组的客户端 - another.author.mod

规则:

  • 没有匹配的规则保留模组作者的 需要一个模组 默认;
  • + 模组标识 强制要求新传入的客户端连接必须经过消费者处理;
  • - 模组唯一标识符 允许不提供该消费者的新客户端接入;
  • 以下规则将被忽略: 固定,这是向后兼容的默认值;
  • 该策略仅适用于服务器端,不会削弱模组客户端自身对服务器提供该模组的要求;
  • 当有效服务器要求为可选时,允许缺少消费者,但已声明的条件消费者仍必须通过其正常版本和CCS协议兼容性检查;
  • 条件客户端即使作者默认为可选,也会公布其消费者握手,因此服务器可以可靠地强制要求该消费者;
  • 连接尝试开始时,需求策略即被快照。重新加载文件只影响后续的连接尝试,绝不会断开已连接的节点。

这支持跨平台服务器等有意降级运行的场景:作者可以推荐并默认使用 需要模组,同时明确允许服务器管理员接受无法安装该模组的客户端。

隐藏设置

文件:

BepInEx/config/shudnal.ConditionalConfigSync/ConditionalConfigSync.HiddenConfigs.cfg

每行添加一个模组GUID、整段标识符或精确设置标识符:

# 由模组作者注册的每个设置 author.mod # 某个部分中的每个设置 author.mod.Advanced # 精确设置 author.mod.Advanced.Internal multiplier author.mod.Debug.Enable verbose output

模组、部分或精确设置匹配会将受影响的设置标记为在兼容的配置管理器中不可浏览。整模组标识符仅受以下支持: 隐藏配置.cfg; 同步策略.cfg 仍然需要一个区块或精确设置目标。隐藏是一种呈现策略,而非安全边界:该设置仍然存在,其同步行为由以下项单独控制 同步策略.cfg,它的 配置同步模式,以及锁定状态。

典型用途:

  • 从普通配置界面中隐藏高级或危险选项;
  • 简化公共服务器的可见设置;
  • 用一行代码隐藏一个模组的全部设置或整个内部板块;
  • 在配置文件中保留诊断选项,但不要在管理器中公开宣传它们。

调试日志

本地调试设置存储在:

BepInEx/配置/shudnal.ConditionalConfigSync/ConditionalConfigSync.调试.cfg

诊断控制台命令:

条件配置同步调试 条件配置同步调试服务器

服务器策略命令:

条件配置同步_状态 条件配置同步_策略重载 条件配置同步_策略验证 条件配置同步_策略导出
  • 状态 显示已注册的模组、配置模式计数、有效配置归属、隐藏设置、有效模组需求以及策略文件路径;
  • 政策重载 在Unity主线程上立即读取并应用所有策略文件;
  • 政策验证 报告语法错误、重复项、冲突、未知标识符以及被固定模式忽略的规则;
  • 政策转储 写入 条件配置同步.策略转储.txt 包含可直接复制的模组、精确设置和区段标识符,以及作者定义的模式和默认值。

调试日志支持 基础, 详细,以及 追踪 关卡以及可选的模组名称筛选器。正常启动时保持静默;警告和错误信息无需调试日志即可显示。

为了让同步性能分析更准确, 详细 记录日志包的序列化时间、压缩时间、原始大小与传输大小、压缩率,以及是构建还是复用了完整的服务器快照。 追踪 另外记录每个配置值和自定义值的序列化负载大小。这适用于使用模组名称过滤器进行短时间性能分析时,同步大型自定义数据(如生成的定义、图像或其他二进制大对象)的场景。

A 自定义同步值<string> 即使已禁用调试日志,序列化负载达到 128 KiB 时,每个网络会话中的每个同步实例仍会生成一条警告。该警告不会拒绝或更改该值;它只是提示以下情况:发送已解析的结构化或二进制运行时数据可能避免重复的大字符串分配和客户端文本解析。

连接被拒诊断

版本检查断连始终记录为错误,与调试日志配置无关。服务器日志会区分以下情况:

  • 在之前未收到匹配的版本握手 对等节点信息;
  • 旧版或不完整握手省略了CCS协议字段;
  • 报告的CCS协议与要求的协议不符;
  • 远程模组版本或最低版本格式错误;
  • 远程模组版本低于本地最低要求,或远程最低要求高于本地模组版本。

成功接收日志包含远程对等方标识符。新的CCS版本还会将自身包版本作为可选诊断元数据追加到现有协议1握手信息中;旧版协议1对等方仍保持兼容,并显示为 未报告.

在服务器发送《英灵神殿》版本错误之前,CCS会先发送一份有限的结构化断开连接报告,其中包含一个报告ID和一个或多个原因代码。同一报告ID会被写入服务器日志和客户端日志以便关联。当前客户端会将此报告与正在进行的连接尝试关联起来,并在连接失败后保留该报告。 网络 关闭足够长时间以便主菜单显示它,并在新连接、成功准入、显示或短暂超时后丢弃过时的报告。

CCS不会创建或拥有单独的错误窗口。仅当当前连接存在明确的待处理CCS报告时,它才会附加其英文说明;一个通用 版本错误 来自另一个兼容性提供程序的连接问题不被视为CCS失败。在Jotunn和ServerSync处理同一表单之前,该报告会附加到现有的Valheim连接错误文本中:

  • 尤顿保持自己的兼容窗口,并接收已丰富的连接失败文本;
  • 服务器同步可能会将自身的诊断信息附加到同一段原版文本中;
  • 当Jotunn不替换原版面板时,CCS会在其他后缀完成后执行一次幂等的一帧布局规范化。

未注册断开连接报告RPC的旧版客户端仍会收到常规的Valheim版本错误提示,必须通过服务器日志查看详细原因。如果被拒绝的客户端上完全不存在CCS,或CCS在注册其RPC之前就失败了,那么该客户端上就没有任何CCS实现来显示服务器提供的原因。

模组作者

条件配置同步是一个第三方独立依赖项。请勿使用ILRepack将其嵌入,也不要将私有副本打包在单个模组中。

仅供参考:

ConditionalConfigSync.dll

对于直接的编译时 API 使用,将独立的 BepInEx 插件声明为硬依赖:

[硬件依赖("_shudnal.ConditionalConfigSync", BepInDependency.DependencyFlags.HardDependency)]

使用命名空间:

使用 ConditionalConfigSync。

公共API保留熟悉的 配置同步 ServerSync 也使用的名称:

内部静态只读配置同步 configSync = new ConfigSync(pluginID) { DisplayName = pluginName, CurrentVersion = pluginVersion, MinimumRequiredVersion = minimumCompatibleVersion, ModRequired = true };

可选软依赖集成

无需同步配置即可保持完整功能的模组,可以使用官方源/ILRepack适配器,而无需引用 ConditionalConfigSync.dll.

适配器维护位置:

ConditionalConfigSync.API/ConditionalConfigSyncAPI.cs

你可以直接将该源文件复制到模组项目中,或者引用 ConditionalConfigSync.API.dll 在开发过程中,并通过ILRepack/内部化将其合并到最终的模组DLL中。请勿分发 ConditionalConfigSync.API.dll 作为单独的运行时依赖项。

将CCS声明为软BepInEx依赖项,使其在安装时排在消费者之前,而消费者在没有CCS的情况下仍能加载:

// 可选同步需要 CCS 1.0.10 或更新版本。 [BepInDependency( ConditionalConfigSyncAPI.ConfigSync.PluginGuid, BepInDependency.DependencyFlags.SoftDependency)]

此可选集成所需的最低CCS版本为 1.0.10BepInEx 5 无法既编码最低版本又保持依赖为软依赖:其带版本 BepIn依赖 构造函数始终是硬依赖。因此嵌入式适配器会检查 条件配置同步API.配置同步.最低Ccs版本 运行时。

适配器始终返回普通的 BepInEx 配置项<T> 对象:

  • 未检测到CCS:仅本地BepInEx配置;
  • CCS 1.0.5-1.0.9:仅限本地 BepInEx 配置;可选桥接功能有意未激活;
  • CCS 1.0.10 或更高版本:相同的条目通过官方反射桥接注册到 CCS。
var optionalSync = new ConditionalConfigSyncAPI.ConfigSync( pluginID, pluginName, pluginVersion, minimumRequiredVersion: minimumCompatibleVersion, modRequired: false, logger: Logger); ConfigEntry<bool> useDurability = optionalSync.Bind( Config, "Gameplay", "Use durability", true, "Enable durability.", ConditionalConfigSyncAPI.SyncMode.AlwaysServerControlled); ConfigEntry<KeyboardShortcut> snappingKey = optionalSync.Bind( Config, "Controls", "Snapping key", new KeyboardShortcut(KeyCode.LeftShift), "Local snapping key.", ConditionalConfigSyncAPI.SyncMode.AlwaysClientControlled);

助手通过活动的BepInEx插件实例解析桥接,以 _固定大小条件配置同步;它不会扫描 应用程序域 按名称加载程序集。因此,由元数据扫描器加载的被动副本不会被意外选中。

仅当本地非同步回退是有效运行模式时,此模式才适用。如果模组需要同步设置才能保证正常玩法或网络行为,请改用普通的硬依赖。

需要在远程端安装此模组

需要模组 是模组作者对以下情况是否适用的默认兼容性约定: 拥有模组 还必须安装在远程对等端上。这与BepInEx对Conditional Config Sync本身的硬依赖是分开的:

  • 硬依赖要求 CCS 与所属模组安装在同一台机器上;
  • 需要模组 意味着运行该模组的客户端要求服务器提供兼容副本,而服务器则要求连接的客户端提供兼容副本;
  • 模组需求 = 否 允许远端省略所属模组。

默认 固定 完全保留此行为,且无法被服务器策略覆盖:

internal static readonly ConfigSync configSync = new ConfigSync(pluginID) { DisplayName = pluginName, CurrentVersion = pluginVersion, MinimumRequiredVersion = minimumCompatibleVersion, ModRequired = true };

使用 条件模式 仅当作者明确接受服务器管理员可以加强或放宽对以下内容的要求时 即将到来的客户:

internal static readonly ConfigSync configSync = new ConfigSync(pluginID) { DisplayName = pluginName, CurrentVersion = pluginVersion, MinimumRequiredVersion = minimumCompatibleVersion, ModRequired = true, ModRequirementMode = ModRequirementMode.Conditional };

在这个例子中,作者的建议保持不变 需要运行该模组的服务器可能会放置 - 插件ID 在 ConditionalConfigSync.ModRequirements.cfg 接受未安装模组或控制台的客户端。此服务端覆盖设置有意保持不对称:运行模组的客户端仍使用作者的 需要模组 = 真 默认情况下,如果服务器未安装该模组,它会拒绝加入。

有条件消费者与 模组必需 = false 同时也从客户端宣告其版本握手信息。这允许服务器策略使用 + 插件ID 并要求该模组,尽管作者的默认设置为可选。修复后的可选消费者保留原有的单向握手行为。

当某个条件消费者对特定入站连接是可选的时,完全缺失是被接受的。如果客户端确实声明了该消费者,则其常规的模组版本和CCS协议兼容性检查仍然适用。因此,将默认必需的消费者放宽为可选,并不会放宽对仍然拥有该模组的客户端的兼容性范围。反之,如果将默认可选的消费者强制设为必需,且没有明确的 最低要求版本 已提供,服务器将使用现有的必需消费者回退机制。 当前版本 对于这项准入要求,服务器会在连接开始时对生效的需求进行快照,因此实时重载策略只会影响后续的连接尝试,不会断开已有玩家。

当客户端可选实例未收到匹配的服务器握手且连接成功完成时,CCS会将该实例恢复为本地真实来源所有权。其本地值保持可编辑状态,且不会发布到服务器。这不是初始服务器同步,因此 初始同步完成 仍为假且 初始同步已完成 未提升。

最低要求版本 最旧的兼容拥有模组版本,而非自动使用当前发布版本。如果兼容版本跨越多个版本,请将此值保持在最旧的受支持版本,而不要随每个包发布而推进。

当远程副本存在时, 当前版本, 最低要求版本,以及 CCS 通信协议用于兼容性检查。延迟注册或 请求完整同步() 不重复连接准入,因此请配置两者 需要模组 和 模组需求模式 在创建 配置同步 实例。

正在查询远程消费者

CCS 1.0.9 公开了一个稳定的能力查询接口,用于针对可选的点对点功能,该功能应仅面向运行兼容消费者模组副本的对等节点。

远程消费者状态 state = ConditionalConfigSync.GetRemoteConsumerState(pluginID, peerUid); 是否支持 supported = ConditionalConfigSync.HasCompatibleConsumer(pluginID, peerUid);

对等用户ID 是瓦尔海姆路由的对等节点UID(网络对等体.唯一标识符),这也是由 ZRoutedRpc返回的状态是。

  • 未知 CCS目前无法确定该能力,例如在节点准入之前、断开连接之后、服务端查询没有本地消费者/版本检查可供比对时、未注册的消费者在另一客户端上静默时,或旧版服务端不发布跨客户端能力状态时;
  • 缺失 - 加入完成,但对等方未通告一个消费者,而已安装的副本预期在CCS版本握手期间进行通告;
  • 不兼容 - 对等方通告了消费者,但其常规CCS版本/协议兼容性检查未通过此关系;
  • 兼容 - 已向消费者进行宣传,并通过了适用的CCS版本/协议兼容性检查。

服务器直接从现有的 版本检查 握手状态。对于客户端到客户端的查询,服务器会在以下操作后为每个接收者生成一个紧凑的快照 同行信息 并且只发送 对等方 UID + 客户 GUID + 状态;原始消费者版本、配置数据和握手负载均不对外暴露。客户端只会收到其自身已通告的消费者GUID对应的条目,因此此API是面向本地参与消费者的兼容性查询,而非远程模组列表枚举机制。这是能力传播,不是第二次消费者握手,且CCS不会为消费者模组传输应用负载。

对于客户端到客户端的发现,服务器会复用其收到的每一个已解析的CCS消费者握手。如果两个对等端通告了相同的消费者GUID,则直接比较它们通告的版本范围和CCS协议,因此当该消费者未安装在服务器上时这也适用。当服务器确实注册了该消费者时,其常规验证结果会作为附加要求强制执行,而缺失的握手可以被报告为 缺失 当已知该消费者在每次安装时都会进行广告宣传时。如果没有匹配的服务端消费者,则静默目标仍会存在 未知 而不是被猜测为缺席; 有兼容消费者 两者均为假 未知 和 缺失。修复后的可选消费者有意不从客户端进行通告,因此无法通过此API提供跨客户端能力发现。当对等方加入或离开时,能力状态会刷新,并在关闭/重新连接时清除。

调用这些API的模组必须声明Conditional Config Sync 1.0.9或更高版本为其最低依赖项。较旧的CCS端仍保持协议兼容;它们只是不提供跨客户端能力快照。

用一次调用注册现有的 BepInEx 条目及其模式:

ConfigEntry<float> damage = Config.Bind( "Gameplay", "Damage multiplier", 1f, "Server gameplay setting"); configSync.AddConfigEntry( damage, ConfigSyncMode.AlwaysServerControlled);

使用 始终由服务器控制 当该设置控制一个必须在服务器和所有客户端之间保持结果一致的通用机制时。不要将此类设置留空。 条件 仅仅为了通过策略使其可配置:允许一个客户端恢复本地值,就可能导致共享计算、事件、状态转换或网络可见行为出现分歧。

或者在一次调用中绑定并注册:

同步配置项<bool> 显示面板 = configSync.添加配置项( 配置, "界面", "显示状态面板", true, new 配置描述("本地UI设置"), 配置同步模式.始终由客户端控制);

对于策略控制的设置,请在注册后指定默认所有权,而无需分配第二个属性:

同步配置项<float> 缩放 = 配置同步.添加配置项( 配置, "Gameplay", "世界缩放", 1f, 新建 配置描述("可通过 SyncPolicy 重新分配"), 配置同步模式.条件, 默认由服务器控制: true);

兼容性重载仍然可用:

configSync.AddConfigEntry(entry); // 有条件的,默认由服务器控制 configSync.AddConfigEntry(entry, false); // 有条件的,默认由客户端控制

直接传递模式/默认值可防止临时的服务器控制注册状态,并避免初始化期间重复的策略状态转换。

运行时值也可用:

public static readonly CustomSyncedValue<string> mapData = new(configSync, "Map data", "");

使用 自定义同步值<T> 对于 state。相等的赋值会被其比较器抑制。请使用 序列化自定义同步值<T> 对于类事件数据,即使重复相同的负载,也必须按顺序交付。

随DLL一起提供的XML文件直接在IDE IntelliSense中记录了公共API、赋值模式、比较器、优先级、版本检查和集成细节。

有效配置状态

每个已注册的配置包装器都会为配置界面和诊断暴露只读元数据:

  • 默认服务器控制 返回由该模组选择的标准化归属;
  • 服务器控制 返回当前生效的所有权,或在策略状态初始化前返回规范化的模组默认值;
  • 策略状态是否已初始化 报告当前服务器会话是否有可用的策略状态;
  • 同步是否被覆盖 只报告会改变模组所定义所有权的政策变动;
  • 有效覆盖 识别 强制服务器控制 或 强制客户端控制;
  • 隐藏 报告有效的隐藏状态;
  • 同步策略控制状态 区分可用的策略控制操作与缺少兼容的服务器会话、缺少管理员访问权限或固定所有权模式;
  • 可更改同步策略 是一个便捷布尔值,仅当以下情况时为真 同步策略控制状态 是 可用;
  • 切换同步策略() 请求对方的有效所有权,并将由此产生的精确设置规则持久化到服务器上。

符合模组默认值的策略规则被有意报告为 无,因为它不会改变运行时行为。这些属性是对现有协议已承载状态的本地只读视图,不会新增网络格式。

协议兼容性

条件配置同步使用独立的数值型通信协议版本,与DLL和包版本无关。

首个公开版本采用协议 1。客户端和服务器必须使用相同的协议版本。只有当引入不兼容的网络格式变更时,协议号才会增加;只要通信契约保持兼容,普通的库更新不需要提升协议版本。

条件模组需求复用现有的版本握手数据包,不新增线路字段。针对CCS 1.0.5编译的现有使用方仍可保持 固定模式 默认情况下,无需重新构建即可针对较新的核心 DLL 运行。只有使用新 条件模式 API需将其最低依赖项声明为更新的CCS包。

策略控制支持通过在现有锁定豁免条目中可选的尾部能力字段进行通告。较旧的客户端会忽略额外的载荷,而较新的客户端在连接到未通告该功能的服务器时,会保持交互式策略控制处于禁用状态。

迟到注册与重新同步

网络会话开始后注册的配置和自定义值会自动处理:

  • 服务器会批量处理新注册的值,并广播它们的当前状态;
  • 注册值之后的客户端 初始同步完成 请求与服务器进行完全重新同步;
  • 同一帧内的多次注册会合并为一次操作。

A 配置同步 在正常连接启动窗口之后创建的实例也会注册其RPC处理程序,并自动请求其第一个完整包。重建动态注册集的模组可以调用 配置同步.请求完整同步() 明确地。该方法返回 假 未连接远程服务器时。

连接准入和模组版本验证仍在《英灵神殿》的正常对等握手过程中进行。需要强制执行版本的模组应创建其 配置同步 连接前的实例;延迟重新同步会更新数据,但不会追溯重复已完成的连接检查。

生命周期与诊断事件

每个 配置同步 实例为需要重建派生运行时状态或提供自有诊断信息的模组暴露可选事件:

  • 初始同步完成 在客户端应用了第一个完整服务器包之后;
  • 服务器连接重置 在服务器数值清除且本地备用数值恢复后;
  • 政策状态已变更, 服务器控制已更改,以及 隐藏状态已改变 当政策发生有效变更时;
  • 锁定状态已变更 当有效锁定或管理员豁免发生变化时;
  • 同步被拒绝 当软件包或外发更新因权限、数据格式错误、队列溢出或 20 MiB 安全限制而被拒绝时。

订阅者异常会被隔离并记录日志,因此单个消费者无法中断其余模组或条目的同步。完整的使用说明包含在 XML 文档中。

为何独立依赖

与嵌入同步源文件或对私有DLL进行ILRepack相比:

  • 所有依赖模组均使用同一个受维护的实现;
  • 对网络、策略、序列化、授权或配置管理器集成的修复只需更新此包;
  • 避免重复的 Harmony 补丁、监视器、命令和静态注册表;
  • 服务器管理员可为所有参与的模组获得一个通用策略层;
  • 依赖模组包保持更小更简单;
  • 兼容的 1.x 版本保持核心程序集标识稳定,因此已编译的依赖模组无需仅为获取运行时修复而重新构建。

对于Thunderstore,将此包添加到模组的依赖项中。不要将任何一个Conditional Config Sync DLL复制到依赖模组自己的包中。

与服务端同步的功能差异

分配与隔离

  • 作为独立的 BepInEx 硬依赖项提供,而不是通过 ILRepack 嵌入。
  • 使用专用命名空间、BepInEx GUID、Harmony ID、RPC名称和包格式。
  • 不会修改或拦截其他模组使用的ServerSync实例。
  • 检测并拒绝不受支持的嵌入式条件配置同步副本。

配置所有权与策略

  • 在客户端上保留独立的本地和活动服务器值。
  • 支持在服务器控制状态与客户端控制状态之间进行运行时切换。
  • 添加三种显式配置模式: 始终由服务器控制, 有条件的和 始终客户端控制.
  • 添加服务器端 同步策略.cfg 覆盖精确设置和完整部分的替代项。
  • 添加可选加入 条件模式 通过招生政策 模组要求.cfg,保留固定 模组必需 现有消费者的行为。
  • 允许兼容的配置界面请求经管理员授权的精确设置策略切换,同时保持策略文件作为持久可信来源。
  • 添加整个模组、区段级别以及精确设置 隐藏配置.cfg Configuration Manager 可见性规则。
  • 将有效配置状态与服务器值一起发送。

锁定与管理

  • 保留 ServerSync 中熟悉的锁定和管理员豁免模型。
  • 即使配置已解锁,也会保护锁定设置本身。
  • 拒绝非管理员网络尝试更改受保护的锁。
  • 将已解锁的非管理员发布视为显式的模组选择加入,并默认禁用。
  • 在客户端运行时和服务器上分别重新评估写入权限。
  • 使用已连接的对等方身份进行当前的英灵神殿管理员检查并生成更清晰的日志。
  • 在应用数值前验证整个客户端更新,并仅重新分发服务器权威状态。

自定义同步值

  • 区分类似状态的 自定义同步值<T> 来自类事件 序列化自定义同步值<T>.
  • 支持显式 分配本地值, 若有变更则分配本地值,以及 分配本地值并通知 行为。
  • 支持为集合和域类型自定义相等比较器。
  • 支持优先级并保持序列值的顺序。
  • 原地修改自定义值对象、集合、数组或其他引用的模组必须调用 通知已变更() 在变更之后。发布该变更本就要求这样做,现在这还会使可复用的全量同步快照失效。
  • 在活动同步期间安全地延迟传出更新,而不是丢弃更改。

序列化与网络

  • 普通 配置项 数值使用基于本地设置类型的 BepInEx TOML 转换。
  • 自定义值保留类型化的 Valheim 包序列化并支持 可序列化参数.
  • 使用带长度前缀的条目,以便隔离未知的服务器条目,并严格验证客户端更新。
  • 保留旧版客户端 配置状态 仅在符合服务器策略时才声称线路兼容,同时绝不信任或转发它们。
  • 在接受客户端更新后构建新的规范服务器包,并将发起客户端包含在结果中。
  • 增加压缩、分片、队列限制、负载限制以及更清晰的故障日志记录。
  • 按权威状态修订版和管理员类别缓存完整的服务器同步快照,包括已压缩的传输数据,以便后续客户端无需重复序列化和压缩未变更的状态。
  • 当同步配置、自定义值、生效的策略状态、已接受的客户端更新或注册发生变更时,使这些快照失效;完整重新同步和完全权威校正使用同一缓存。
  • 添加可选的包计时/大小诊断功能,在禁用诊断时不改变序列化字节。
  • 添加独立的数字协议版本,支持客户端/服务器精确匹配。
  • 支持自动延迟注册和显式完全重新同步。

诊断与文档

  • 增加稳定的/重试的策略读取,使部分编辑器写入不会替换活动策略。
  • 在相关会话或引导过程结束时,清理策略监视器、网络缓存、待处理队列、已注册的会话处理器以及 Harmony 所有权。
  • 为单值更新添加带有配置/自定义值名称的每模组接收日志。
  • 包含可选的过滤调试日志记录以及服务器策略状态/重载/验证/转储命令。
  • 为重要的公共 API 成员提供 XML IntelliSense 文档和元数据描述。
  • 保留架构、兼容性规则、被拒绝的备选方案、回归风险和发布要求 项目背景.md.

迁移说明

在模组中使用条件配置同步会为该模组选择其同步实现和协议。服务器和客户端应同时更新依赖模组和此依赖项。其他使用ServerSync的已安装模组不受影响。

许可与鸣谢

原始条件配置同步贡献内容根据以下协议发布: 无许可证该项目基于ServerSync方案并改编了其代码作为基础;适用的ServerSync部分仍受其MIT-0条款约束。部分实现和兼容性思路参考了Jotunn。保留的声明可在以下位置查看 第三方声明.md.

安全与隐私

条件配置同步:

  • 不包含遥测数据,也不会向外部服务发送任何数据;
  • 不在活动的英灵神殿客户端/服务器会话之外发起任何HTTP请求或打开任何网络连接;
  • 不下载、更新或执行外部程序;
  • 不访问 Windows 注册表,也不附带本机库;
  • 仅通过当前服务器与其连接的客户端之间的英灵神殿RPC连接进行通信;
  • 将客户端配置包视为不可信输入,在服务器端验证权限,并且绝不转发原始客户端包;
  • 仅将其策略、调试、转储和诊断文件写入 BepInEx/配置/shudnal.条件配置同步;
  • 仅使用反射访问 Valheim 运行时成员,这些成员的可访问性与公开化开发程序集不同;
  • 发布未混淆的二进制文件、XML API 文档和源代码。

链接

Valheim: 英灵神殿 的热门 MOD

探索适用于 Valheim: 英灵神殿 的最佳MOD,带来新功能、升级画面,以及令人兴奋的方式来改变您的游戏体验。

使用 Xmod 解锁 Valheim: 英灵神殿 的全部潜力 — 今天就探索这些顶级 MOD!