Skip to content

端(Sides)

字数
1731 字
阅读时间
7 分钟

文章翻译自官方文档:

端(Sides)

与许多其他程序一样,Minecraft 遵循客户端-服务器架构,其中客户端负责显示数据,而服务器负责更新数据。当我们使用这些术语时,我们对它们的含义有一个相当直观的理解……对吧?

事实证明,并非如此。许多混淆源于 Minecraft 根据上下文有两种不同的端概念:物理端逻辑端

逻辑端与物理端

物理端

当您打开 Minecraft 启动器,选择一个 Minecraft 安装并按下“播放”按钮时,您启动了一个物理客户端。这里的“物理”一词用于表示“这是一个客户端程序”。这意味着客户端功能(例如所有渲染内容)在此可用,并且可以根据需要使用。相比之下,物理服务器(也称为专用服务器)是当您启动 Minecraft 服务器 JAR 时启动的内容。虽然 Minecraft 服务器带有一个基本的 GUI,但它缺少所有仅客户端的功能。最显著的是,这意味着服务器 JAR 中缺少各种客户端类。在物理服务器上调用这些类将导致缺少类错误,即崩溃,因此我们需要防范这种情况。

逻辑端

逻辑端主要关注 Minecraft 的内部程序结构。逻辑服务器是游戏逻辑运行的地方。诸如时间和天气变化、实体更新、实体生成等都在服务器上运行。各种数据(例如库存内容)也是服务器的责任。另一方面,逻辑客户端负责显示所有需要显示的内容。Minecraft 将所有客户端代码隔离在 net.minecraft.client 包中,并在一个称为“渲染线程”的单独线程中运行它,而其他所有内容都被视为公共代码(即客户端和服务器共用的代码)。

有什么区别?

物理端和逻辑端之间的区别最好通过两种场景来说明:

  1. 玩家加入多人游戏世界:这相当简单。玩家的物理(和逻辑)客户端连接到位于其他地方的物理(和逻辑)服务器——玩家不关心服务器在哪里;只要他们可以连接,这就是客户端所知道的全部,也是客户端需要知道的全部。
  2. 玩家加入单人游戏世界:这里事情变得有趣了。玩家的物理客户端启动一个逻辑服务器,然后以逻辑客户端的角色连接到同一台机器上的逻辑服务器。如果您熟悉网络,可以将其视为连接到 localhost(仅在概念上;实际上没有涉及套接字或类似的东西)。

这两种场景也展示了主要问题:如果逻辑服务器可以与您的代码一起工作,这并不能保证物理服务器也能与您的代码一起工作。这就是为什么您应该始终使用专用服务器进行测试以检查意外行为。由于客户端和服务器分离不正确而导致的 NoClassDefFoundErrorClassNotFoundException 是 Mod 开发中最常见的错误之一。另一个常见的错误是使用静态字段并从两个逻辑端访问它们;这尤其棘手,因为通常没有任何迹象表明有问题。

提示:如果您需要将数据从一端传输到另一端,您必须发送一个数据包。

在 NeoForge 代码库中,物理端由一个名为 Dist 的枚举表示,而逻辑端由一个名为 LogicalSide 的枚举表示。

信息:历史上,服务器 JAR 中有客户端没有的类。在现代版本中不再是这样;物理服务器可以说是物理客户端的一个子集。

执行端特定操作

Level#isClientSide()

这个布尔检查将是您检查端的最常用方式。在 Level 对象上查询此字段可以确定该级别所属的逻辑端:如果此字段为 true,则该级别在逻辑客户端上运行。如果该字段为 false,则该级别在逻辑服务器上运行。因此,物理服务器在此字段中将始终为 false,但我们不能假设 false 意味着物理服务器,因为此字段在物理客户端内的逻辑服务器(即单人游戏世界)中也可能为 false

每当您需要确定是否应运行游戏逻辑和其他机制时,请使用此检查。例如,如果您希望每次玩家点击您的方块时对玩家造成伤害,或者让您的机器将泥土加工成钻石,您应确保 #isClientSidefalse 后再执行这些操作。将游戏逻辑应用于逻辑客户端可能会导致不同步(幽灵实体、不同步的统计数据等)或在最坏情况下导致崩溃。

提示:此检查应作为您的默认选择。每当您有 Level 可用时,请使用此检查。

FMLEnvironment.dist

FMLEnvironment.distLevel#isClientSide() 检查的物理端对应项。如果此字段为 Dist.CLIENT,则表示您在物理客户端上。如果该字段为 Dist.DEDICATED_SERVER,则表示您在物理服务器上。

@Mod

在处理仅客户端类时,检查物理环境非常重要。推荐的方式是通过指定单独的 @Mod 注解来分离应仅在特定物理端执行的代码,将 dist 参数设置为应加载 Mod 类的物理端:

java
@Mod("examplemod")
public class ExampleMod {
    public ExampleMod(IEventBus modBus) {
        // 在此执行应在两端执行的逻辑
    }
}

@Mod(value = "examplemod", dist = Dist.CLIENT) 
public class ExampleModClient {
    public ExampleModClient(IEventBus modBus) {
        // 在此执行应仅在物理客户端执行的逻辑
        Minecraft.getInstance().whatever();
    }
}

@Mod(value = "examplemod", dist = Dist.DEDICATED_SERVER) 
public class ExampleModDedicatedServer {
    public ExampleModDedicatedServer(IEventBus modBus) {
        // 在此执行应仅在物理服务器执行的逻辑
    }
}

提示:通常期望 Mod 在任一端都能工作。这尤其意味着,如果您正在开发仅客户端的 Mod,您应验证该 Mod 是否确实在物理客户端上运行,如果没有,则不执行任何操作。

贡献者

The avatar of contributor named as 小飘 小飘

文件历史