zh_cn:tutorial:persistent_states
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
zh_cn:tutorial:persistent_states [2023/12/15 08:10] – created & translation started dreamuniverse | zh_cn:tutorial:persistent_states [2024/07/10 03:31] (current) – several corrections to the title and specified words dreamuniverse | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== | + | ====== 持久状态 ====== |
+ | |||
+ | ===== 引言 | ||
通常情况下,我们的模组中带有与玩家相关的信息,或是在玩家死亡、服务器重启时我们希望保留的世界信息。\\ | 通常情况下,我们的模组中带有与玩家相关的信息,或是在玩家死亡、服务器重启时我们希望保留的世界信息。\\ | ||
Line 16: | Line 18: | ||
那么,我们如何能让 Fabric 保存这些信息,或者其他我们想保存的模组或游戏数据,以供下次玩家加载世界或重新登录时能读取到这些信息? | 那么,我们如何能让 Fabric 保存这些信息,或者其他我们想保存的模组或游戏数据,以供下次玩家加载世界或重新登录时能读取到这些信息? | ||
- | ====== 简单的消息发送——数据包 | + | ===== 简单的消息发送——数据包 ===== |
首先,既然我们的游戏保存在逻辑服务器上,那么我们就让服务器在检测到玩家挖掘泥土方块时向玩家发送一个数据包,并将其显示在玩家的聊天区内。\\ | 首先,既然我们的游戏保存在逻辑服务器上,那么我们就让服务器在检测到玩家挖掘泥土方块时向玩家发送一个数据包,并将其显示在玩家的聊天区内。\\ | ||
Line 103: | Line 105: | ||
那么,如果我们把上次游戏结束时的计数写入到了本地(如硬盘某处),我们就可以在游戏启动时读取并加载它,作为计数器的初始值。这样一来我们就可以继续统计下去。\\ | 那么,如果我们把上次游戏结束时的计数写入到了本地(如硬盘某处),我们就可以在游戏启动时读取并加载它,作为计数器的初始值。这样一来我们就可以继续统计下去。\\ | ||
但是,我们**必须**要做到这一点:数值要在游戏关闭时保存,在游戏启动时读取并加载。\\ | 但是,我们**必须**要做到这一点:数值要在游戏关闭时保存,在游戏启动时读取并加载。\\ | ||
- | 想要达到这一目的,方法千千万,不过我们在这里使用 Minecraft 提供给我们的方法:实现一个扩展了 ' | + | 想要达到这一目的,方法千千万,不过我们在这里使用 Minecraft 提供给我们的方法:实现一个继承了 '' |
- | ====== 状态持久化 | + | ===== 状态持久化详述 |
首先,我们在项目目录新建一个名为 '' | 首先,我们在项目目录新建一个名为 '' | ||
Line 128: | Line 130: | ||
</ | </ | ||
- | 注:在扩展 | + | 注:在继承 |
- | * '' | + | * '' |
+ | | ||
- | Next add the following function to that same file: | + | 接下来,将这个方法添加到同一个文件中: |
<code java> | <code java> | ||
public class StateSaverAndLoader extends PersistentState { | public class StateSaverAndLoader extends PersistentState { | ||
- | // ... (Previously written code) | + | // ... (先前写好的代码部分) |
public static StateSaverAndLoader createFromNbt(NbtCompound tag) { | public static StateSaverAndLoader createFromNbt(NbtCompound tag) { | ||
Line 147: | Line 150: | ||
</ | </ | ||
- | This function does the opposite of '' | + | 这个方法的作用与 |
- | * Note: how we pull out the int we stored earlier with '' | + | * 注:与 |
- | Now we just need to add one more utility function which hooks everything up together. This function will take a '' | + | 现在我们再添加一个工具类方法,这个方法需要导入 |
+ | 当创建时,其调用我们刚刚写到的 | ||
<code java> | <code java> | ||
public class StateSaverAndLoader extends PersistentState { | public class StateSaverAndLoader extends PersistentState { | ||
- | // ... (Previously written code) | + | // ... (先前写好的代码部分) |
private static Type< | private static Type< | ||
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | null // Supposed to be an ' | + | null // 此处理论上应为 |
); | ); | ||
public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
- | // (Note: arbitrary choice to use ' | + | // (注:如需在任意维度生效,请使用 |
PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | ||
- | // The first time the following | + | // 当第一次调用了方法 |
- | // stores it inside the ' | + | // ' |
- | // ' | + | |
StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | ||
- | // If state is not marked | + | // 若状态未标记为脏(dirty),当 |
- | // Technically it's ' | + | // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 |
- | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | + | // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 |
- | // Besides, it's literally just setting a bool to true, and the only time there' | + | // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见) |
- | // there were no actual change to any of the mods state (INCREDIBLY RARE). | + | |
state.markDirty(); | state.markDirty(); | ||
Line 185: | Line 187: | ||
</ | </ | ||
- | Your '' | + | 现在,您的 |
<code java> | <code java> | ||
Line 211: | Line 213: | ||
private static Type< | private static Type< | ||
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | null // Supposed to be an ' | + | null // 此处理论上应为 |
); | ); | ||
public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
- | // (Note: arbitrary choice to use ' | + | // (注:如需在任意维度生效,请使用 |
PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | ||
- | // The first time the following | + | // 当第一次调用了方法 |
- | // stores it inside the ' | + | // ' |
- | // ' | + | |
StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | ||
- | // If state is not marked | + | // 若状态未标记为脏(dirty),当 |
- | // Technically it's ' | + | // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 |
- | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | + | // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 |
- | // Besides, it's literally just setting a bool to true, and the only time there' | + | // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见) |
- | // there were no actual change to any of the mods state (INCREDIBLY RARE). | + | |
state.markDirty(); | state.markDirty(); | ||
Line 237: | Line 237: | ||
</ | </ | ||
- | You'll also have to update your class which '' | + | 相应地,您也需要将实现了 |
<code java> | <code java> | ||
Line 253: | Line 253: | ||
public class ExampleMod implements ModInitializer { | public class ExampleMod implements ModInitializer { | ||
- | public static final String MOD_ID = "your_unique_mod_id_change_me_please"; | + | public static final String MOD_ID = "您的MOD_ID"; |
public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
Line 262: | Line 262: | ||
if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | ||
StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | ||
- | // Increment the amount of dirt blocks that have been broken | + | // 当泥土方块被挖掘时增加计数 |
serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
- | // Send a packet to the client | + | // 向客户端发送数据包 |
MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
Line 281: | Line 281: | ||
</ | </ | ||
- | If you run your game now, you should see the counter going up, but now, if you fully close Minecraft, and open it again, you should see the number keeps increasing from where it left off. | + | 如果您现在运行游戏,您会发现计数器正常递增,但现在即使您关闭游戏并重新启动,计数器也会从退出时的位置继续递增。 |
+ | |||
+ | 有一点您有可能会忽略,'' | ||
+ | 这对我们模组中的特定类型数据是很好的,表明它们能正常工作。但更多时候,我们期望数据是因玩家而异的。 | ||
+ | 正如我们开篇所提,如果我们想要保留**任意玩家**的**特定方块**的挖掘数据,这时我们要怎么做? | ||
- | What you might or might not expect is that '' | + | ===== 因玩家而异的持久化状态 |
- | ====== Player Specific Persistent State ====== | + | |
- | We can store player-specific data by extending what we already wrote. | + | 我们可以将我们所写的代码再改进一下,这样就可以存储每个玩家的特定数据了。 |
- | First write a new class '' | + | 首先,新建一个名为 |
- | * Extremely important note: Since we'll be creating a HashMap | + | * 特别提示: 我们会创建 |
+ | 如果您期望在客户端侧获知部分或全部的 ''**PlayerData**'' | ||
<code java> | <code java> | ||
Line 298: | Line 302: | ||
</ | </ | ||
- | To simplify, we're just continuing with our simple example, but you could put any fields you'd like in the '' | + | 为尽可能简明地说明问题,在示例代码中我们依然使用这个简单的例子,但您在实际应用中可以向 |
- | Next, we'll modify the top of our '' | + | 接下来,将 |
<code java> | <code java> | ||
- | // ... (Previous imports) | + | // ... (其他的引用包) |
import java.util.HashMap; | import java.util.HashMap; | ||
import java.util.UUID; | import java.util.UUID; | ||
Line 313: | Line 317: | ||
public HashMap< | public HashMap< | ||
- | // ... (Rest of the code) | + | // ... (代码的剩余部分) |
} | } | ||
</ | </ | ||
- | Note: We create a '' | + | 注:我们创建了一个关于 |
+ | Hashmap 即哈希表,简单而言,在本例中,您向表中给出一个特定的“键值”(key),表从 | ||
+ | 我们使用 | ||
- | Let's add a utility function to '' | + | 接下来我们向 |
<code java> | <code java> | ||
public class StateSaverAndLoader extends PersistentState { | public class StateSaverAndLoader extends PersistentState { | ||
- | // ... (Previously written code) | + | // ... (先前写好的代码部分) |
public static PlayerData getPlayerState(LivingEntity player) { | public static PlayerData getPlayerState(LivingEntity player) { | ||
StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | ||
- | // Either get the player by the uuid, or we don't have data for him yet, make a new player state | + | // 根据 UUID 获取对应玩家的状态,如果没有该玩家的数据,就创建一个新的玩家状态。 |
PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | ||
Line 339: | Line 345: | ||
- | * If our '' | + | * 若类 |
- | Now update the class which '' | + | 接下来将实现了 |
<code java> | <code java> | ||
Line 357: | Line 363: | ||
public class ExampleMod implements ModInitializer { | public class ExampleMod implements ModInitializer { | ||
- | public static final String MOD_ID = "your_unique_mod_id_change_me_please"; | + | public static final String MOD_ID = "您的MOD_ID"; |
public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
Line 363: | Line 369: | ||
@Override | @Override | ||
public void onInitialize() { | public void onInitialize() { | ||
+ | // 注册一个方块挖掘事件监听器 | ||
PlayerBlockBreakEvents.AFTER.register((world, | PlayerBlockBreakEvents.AFTER.register((world, | ||
if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | ||
StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | ||
- | // Increment the amount of dirt blocks that have been broken | + | // 当泥土方块被挖掘时增加计数 |
serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
Line 372: | Line 379: | ||
playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
- | // Send a packet to the client | + | // 向客户端发送数据包 |
MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
Line 389: | Line 396: | ||
</ | </ | ||
- | You'll also have to modify the class which '' | + | 您同时需要将实现了 |
<code java> | <code java> | ||
Line 405: | Line 412: | ||
client.execute(() -> { | client.execute(() -> { | ||
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
}); | }); | ||
}); | }); | ||
Line 413: | Line 420: | ||
</ | </ | ||
- | If you ran the client now, it would seem as if everything is working, but we are forgetting a crucial step: We haven' | + | 如果您现在运行客户端,看上去一切工作正常,但我们忘记了非常关键的一点:我们没有使用 |
- | The updated functions are as follows: | + | 改动后的方法代码如下所示: |
<code java> | <code java> | ||
public class StateSaverAndLoader extends PersistentState { | public class StateSaverAndLoader extends PersistentState { | ||
- | // ... (Rest of code) | + | // ... (代码的剩余部分) |
@Override | @Override | ||
Line 456: | Line 463: | ||
} | } | ||
- | // ... (Rest of code) | + | // ... (代码的剩余部分) |
} | } | ||
</ | </ | ||
- | The final '' | + | 最终的 |
<code java> | <code java> | ||
Line 515: | Line 522: | ||
private static Type< | private static Type< | ||
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | null // Supposed to be an ' | + | null // 此处理论上应为 |
); | ); | ||
public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
- | // (Note: arbitrary choice to use ' | + | // (注:如需在任意维度生效,请使用 |
PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | ||
- | // The first time the following | + | // 当第一次调用了方法 |
- | // stores it inside the ' | + | // ' |
- | // ' | + | |
StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | ||
- | // If state is not marked | + | // 若状态未标记为脏(dirty),当 |
- | // Technically it's ' | + | // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 |
- | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | + | // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 |
- | // Besides, it's literally just setting a bool to true, and the only time there' | + | // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见) |
- | // there were no actual change to any of the mods state (INCREDIBLY RARE). | + | |
state.markDirty(); | state.markDirty(); | ||
Line 542: | Line 547: | ||
StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | ||
- | // Either get the player by the uuid, or we don't have data for him yet, make a new player state | + | // 根据 UUID 获取对应玩家的状态,如果没有该玩家的数据,就创建一个新的玩家状态。 |
PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | ||
Line 550: | Line 555: | ||
</ | </ | ||
- | Running the client now, all our player-specific data is correctly saved. | + | 接下来运行客户端,玩家特定的数据现在都可以被正确地保存了。 |
- | * Note: each time you restart the minecraft client with fabric, you're assigned a new UUID, so it may seem like it's not working, but that's just because of the developer environment. | + | * 注:每次您使用 Fabric 调试启动客户端时,您所分配到的 |
- | Just remember if you add new fields to '' | + | 请谨记,只要您向 |
- | ====== Initial Sync ====== | + | ===== 内联同步 |
- | What if it's important for our mod that as soon as a player joins they receive some or all the PlayerData | + | 那么,当玩家加入服务器时,他们应当收到与他们相关的部分或全部玩家数据(''**PlayerData**'' |
+ | 对于这一点,当玩家加入世界时,我们会向玩家发送一个用于内联同步('' | ||
- | Modify your class which '' | + | 现在,我们将实现了'' |
<code java> | <code java> | ||
Line 576: | Line 582: | ||
public class ExampleMod implements ModInitializer { | public class ExampleMod implements ModInitializer { | ||
- | public static final String MOD_ID = "your_unique_mod_id_change_me_please"; | + | public static final String MOD_ID = "您的MOD_ID"; |
public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
Line 596: | Line 602: | ||
if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | ||
StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | ||
- | // Increment the amount of dirt blocks that have been broken | + | // 当泥土方块被挖掘时增加计数 |
serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
Line 602: | Line 608: | ||
playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
- | // Send a packet to the client | + | // 向客户端发送数据包 |
MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
Line 619: | Line 625: | ||
</ | </ | ||
- | Then modify your class which '' | + | 随后,再将实现了 |
<code java> | <code java> | ||
Line 637: | Line 643: | ||
client.execute(() -> { | client.execute(() -> { | ||
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
}); | }); | ||
}); | }); | ||
Line 646: | Line 652: | ||
client.execute(() -> { | client.execute(() -> { | ||
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
}); | }); | ||
}); | }); | ||
Line 653: | Line 659: | ||
</ | </ | ||
- | As soon as you join the world/ | + | 这样一来,当您进入本地世界或服务器时,您就会看到有一条消息提示您已经挖掘了多少泥土方块。 |
- | * Note: The '' | + | * 注①:我们在客户端侧所创建的 |
- | * Note: each time you restart the minecraft client with fabric, you're assigned a new UUID, so it may seem like it's not working, but that's just because of the developer environment. | + | * 注②:每次您使用 Fabric 调试启动客户端时,您所分配到的 |
- | ====== More Involved Player Data ====== | + | ===== 更复杂的玩家数据 |
- | And just for good measure, let's see an example of how our '' | + | 现在我们已经不能满足单一方块的统计需求了,我们来看另一个例子:如果我们的 |
- | Let's say this is our '' | + | 假设我们的 |
<code java> | <code java> | ||
Line 679: | Line 685: | ||
</ | </ | ||
- | This would be our '' | + | 我们的 |
<code java> | <code java> | ||
Line 750: | Line 756: | ||
private static Type< | private static Type< | ||
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
- | null // Supposed to be an ' | + | null // 此处理论上应为 |
); | ); | ||
+ | |||
public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
- | // (Note: arbitrary choice to use ' | + | // (注:如需在任意维度生效,请使用 |
PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); | ||
- | + | ||
- | // The first time the following | + | // 当第一次调用了方法 |
- | // stores it inside the ' | + | // ' |
- | // ' | + | |
StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, | ||
- | + | ||
- | // If state is not marked | + | // 若状态未标记为脏(dirty),当 |
- | // Technically it's ' | + | // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 |
- | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | + | // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 |
- | // Besides, it's literally just setting a bool to true, and the only time there' | + | // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见) |
- | // there were no actual change to any of the mods state (INCREDIBLY RARE). | + | |
state.markDirty(); | state.markDirty(); | ||
+ | |||
return state; | return state; | ||
} | } | ||
Line 777: | Line 781: | ||
StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | StateSaverAndLoader serverState = getServerState(player.getWorld().getServer()); | ||
- | // Either get the player by the uuid, or we don't have data for him yet, make a new player state | + | // 根据 UUID 获取对应玩家的状态,如果没有该玩家的数据,就创建一个新的玩家状态。 |
PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), | ||
Line 785: | Line 789: | ||
</ | </ | ||
- | Our classes which implement | + | 对已经实现了 |
<code java> | <code java> | ||
Line 803: | Line 807: | ||
client.execute(() -> { | client.execute(() -> { | ||
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
}); | }); | ||
}); | }); | ||
Line 812: | Line 816: | ||
client.execute(() -> { | client.execute(() -> { | ||
- | client.player.sendMessage(Text.literal(" | + | client.player.sendMessage(Text.literal(" |
}); | }); | ||
}); | }); | ||
Line 834: | Line 838: | ||
public class ExampleMod implements ModInitializer { | public class ExampleMod implements ModInitializer { | ||
- | public static final String MOD_ID = "your_unique_mod_id_change_me_please"; | + | public static final String MOD_ID = "您的MOD_ID"; |
public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
Line 854: | Line 858: | ||
if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | if (state.getBlock() == Blocks.GRASS_BLOCK || state.getBlock() == Blocks.DIRT) { | ||
StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | StateSaverAndLoader serverState = StateSaverAndLoader.getServerState(world.getServer()); | ||
- | // Increment the amount of dirt blocks that have been broken | + | // 当泥土方块被挖掘时增加计数 |
serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
Line 860: | Line 864: | ||
playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
- | // Send a packet to the client | + | // 向客户端发送数据包 |
MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
zh_cn/tutorial/persistent_states.1702627824.txt.gz · Last modified: 2023/12/15 08:10 by dreamuniverse