User Tools

Site Tools


zh_cn:tutorial:persistent_states

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revisionBoth sides next revision
zh_cn:tutorial:persistent_states [2023/12/15 08:10] – created & translation started dreamuniversezh_cn:tutorial:persistent_states [2023/12/17 02:52] – Player Specific Persistent dreamuniverse
Line 103: Line 103:
 那么,如果我们把上次游戏结束时的计数写入到了本地(如硬盘某处),我们就可以在游戏启动时读取并加载它,作为计数器的初始值。这样一来我们就可以继续统计下去。\\ 那么,如果我们把上次游戏结束时的计数写入到了本地(如硬盘某处),我们就可以在游戏启动时读取并加载它,作为计数器的初始值。这样一来我们就可以继续统计下去。\\
 但是,我们**必须**要做到这一点:数值要在游戏关闭时保存,在游戏启动时读取并加载。\\ 但是,我们**必须**要做到这一点:数值要在游戏关闭时保存,在游戏启动时读取并加载。\\
-想要达到这一目的,方法千千万,不过我们在这里使用 Minecraft 提供给我们的方法:实现一个扩展了 '**PersistentState**' 的类。+想要达到这一目的,方法千千万,不过我们在这里使用 Minecraft 提供给我们的方法:实现一个继承了 ''**PersistentState**'' 的类。
  
 ====== 状态持久化 ====== ====== 状态持久化 ======
Line 128: Line 128:
 </code> </code>
  
-注:在扩展 ''**PersistentState**'' 类时,必须实现 ''**writeNbt**''。从功能上讲,我们通过 ''**NbtCompound**'' 将我们要存储到本地的数据进行打包。在本例中,我们将先前创建的 "**public Integer totalDirtBlocksBroken**" 移入了这个文件。+注:在继承 ''**PersistentState**'' 类时,必须实现 ''**writeNbt**''。从功能上讲,我们通过 ''**NbtCompound**'' 将我们要存储到本地的数据进行打包。在本例中,我们将先前创建的 "**public Integer totalDirtBlocksBroken**" 移入了这个文件。
  
-  * ''**NbtCompound**''能直接保存 ''**Integers**''. It has functions for strings, arrays, bools, floats, importantly other ''**NbtCompound**'''s as you'll see soon enough, and even arbitrary bytes. That means, if you want to store some ''**SuperCustomClass**'', what you should do is create a ''**new NbtCompound**'' and pack that new ''**NbtCompound**'' with the fields of your ''**SuperCustomClass**'' and then store it in the main ''**NbtCompound**'' you get passed in. (We're about to do just that!)+  * ''**NbtCompound**''只是保存**整数值**,它还保存着其他类型的数据,甚至是其他的 ''**NbtCompound**'' 数据或者任意的字节数据。 
 +  因此,如果您希望存储一个自定义类,那么您应当新建一个 ''**NbtCompound**'' 子对象,然后将您自定义类的相应字段打包进这个 ''**NbtCompound**'' 子对象中,再传入其父级 ''**NbtCompound**'' 对象。(我们正在为此努力!)
  
-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 148:
 </code> </code>
  
-This function does the opposite of ''**writeNbt**''. It takes in an ''**NbtCompound**'' (the same one we wrote in ''**writeNbt**''), creates a brand ''**new StateSaverAndLoader**'' and stuffs it with the data inside the ''**NbtCompound**''.+这个函数的作用与 ''**writeNbt**'' 相反,它需要传入一个 ''**NbtCompound**'' (在 ''**writeNbt**'' 时写入的同一个对象),之后新建一个 ''**StateSaverAndLoader**'' 以供我们传入在 ''**NbtCompound**'' 中的数据。
  
-  * Note: how we pull out the int we stored earlier with ''**getInt**'' and how the string we pass in is the same one we used in ''**writeNbt**''.+  * 注:与 ''**getInt**'' 读取整数的方式类似,''**writeNbt**'' 传递字符串的方式是一样的。
  
-Now we just need to add one more utility function which hooks everything up together. This function will take a ''**MinecraftServer**'' and from it, get the ''**PersistentStateManager**''''**PersistentStateManager**'' has a function ''**getOrCreate**'' which will use our ''**MOD_ID**'' as a key to see if it has an instance of our ''**StateSaverAndLoader**'' or if it needs to create one. If it needs to create one, it'll call the function we just wrote ''**createFromNbt**'' passing in the previously saved-to-disk ''**NbtCompound**''. Ultimately the function returns the ''**StateSaverAndLoader**'' for the given ''**MinecraftServer**''.+现在我们再添加一个工具类函数,这个函数需要导入 ''**MinecraftServer.PersistentStateManager**''''**PersistentStateManager**'' 有一个名为 ''**getOrCreate**'' 的方法,其中 ''**MOD_ID**'' 作为字段传递给 ''**StateSaverAndLoader**'' 以确定是否有其实例,若没有则创建。\\ 
 +当创建时,其调用我们刚刚写到的 ''**createFromNbt**'' 并将我们已经存储在本地的 ''**NbtCompound**'' 传入进去。最后,这个方法会向给定的 ''**MinecraftServer**'' 返回 ''**StateSaverAndLoader**''
  
 <code java> <code java>
 public class StateSaverAndLoader extends PersistentState { public class StateSaverAndLoader extends PersistentState {
  
-    // ... (Previously written code)+    // ... (先前写好的代码部分)
  
     private static Type<StateSaverAndLoader> type = new Type<>(     private static Type<StateSaverAndLoader> type = new Type<>(
-            StateSaverAndLoader::new, // If there's no 'StateSaverAndLoader' yet create one +            StateSaverAndLoader::new, // 若不存在 'StateSaverAndLoader' 则创建 
-            StateSaverAndLoader::createFromNbt, // If there is a 'StateSaverAndLoader' NBT, parse it with 'createFromNbt' +            StateSaverAndLoader::createFromNbt, // 若存在 'StateSaverAndLoader' NBT, 则调用 'createFromNbt' 传入参数 
-            null // Supposed to be an 'DataFixTypes' enum, but we can just pass null+            null // 此处理论上应为 'DataFixTypes' 的枚举,但我们直接传递为空(null)也可以
     );     );
  
     public static StateSaverAndLoader getServerState(MinecraftServer server) {     public static StateSaverAndLoader getServerState(MinecraftServer server) {
-        // (Note: arbitrary choice to use 'World.OVERWORLD' instead of 'World.END' or 'World.NETHER'.  Any work)+        // (注:如需在任意维度生效,请使用 'World.OVERWORLD' ,不要使用 'World.END' 或 'World.NETHER')
         PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager();         PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager();
  
-        // The first time the following 'getOrCreate' function is called, it creates a brand new 'StateSaverAndLoader' and +        // 当第一次调用了方法 'getOrCreate' 后,它会创建新的 'StateSaverAndLoader' 并将其存储于  'PersistentStateManager' 中。 
-        // stores it inside the 'PersistentStateManager'. The subsequent calls to 'getOrCreate' pass in the saved +        //  'getOrCreate' 的后续调用将本地的 'StateSaverAndLoader' NBT 传递给 'StateSaverAndLoader::createFromNbt'
-        // 'StateSaverAndLoader' NBT on disk to our function 'StateSaverAndLoader::createFromNbt'.+
         StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID);         StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID);
  
-        // If state is not marked dirty, when Minecraft closes, 'writeNbt' won't be called and therefore nothing will be saved. +        // 若状态未标记为脏(dirty),当 Minecraft 关闭时, 'writeNbt' 不会被调用,相应地,没有数据会被保存。 
-        // Technically it's 'cleaner' if you only mark state as dirty when there was actually a change, but the vast majority +        // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 
-        // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to 'markDirty' for them. +        // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 'markDirty'  
-        // Besides, it's literally just setting a bool to true, and the only time there's a 'cost' is when the file is written to disk when +        // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见)
-        // there were no actual change to any of the mods state (INCREDIBLY RARE).+
         state.markDirty();         state.markDirty();
  
Line 185: Line 185:
 </code> </code>
  
-Your ''**StateSaverAndLoader**'' file should look as follows:+现在,您的 ''**StateSaverAndLoader**'' 文件应如下所示:
  
 <code java> <code java>
Line 211: Line 211:
  
     private static Type<StateSaverAndLoader> type = new Type<>(     private static Type<StateSaverAndLoader> type = new Type<>(
-            StateSaverAndLoader::new, // If there's no 'StateSaverAndLoader' yet create one +            StateSaverAndLoader::new, // 若不存在 'StateSaverAndLoader' 则创建 
-            StateSaverAndLoader::createFromNbt, // If there is a 'StateSaverAndLoader' NBT, parse it with 'createFromNbt' +            StateSaverAndLoader::createFromNbt, // 若存在 'StateSaverAndLoader' NBT, 则调用 'createFromNbt' 传入参数 
-            null // Supposed to be an 'DataFixTypes' enum, but we can just pass null+            null // 此处理论上应为 'DataFixTypes' 的枚举,但我们直接传递为空(null)也可以
     );     );
  
     public static StateSaverAndLoader getServerState(MinecraftServer server) {     public static StateSaverAndLoader getServerState(MinecraftServer server) {
-        // (Note: arbitrary choice to use 'World.OVERWORLD' instead of 'World.END' or 'World.NETHER'.  Any work)+        // (注:如需在任意维度生效,请使用 'World.OVERWORLD' ,不要使用 'World.END' 或 'World.NETHER')
         PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager();         PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager();
  
-        // The first time the following 'getOrCreate' function is called, it creates a brand new 'StateSaverAndLoader' and +        // 当第一次调用了方法 'getOrCreate' 后,它会创建新的 'StateSaverAndLoader' 并将其存储于  'PersistentStateManager' 中。 
-        // stores it inside the 'PersistentStateManager'. The subsequent calls to 'getOrCreate' pass in the saved +        //  'getOrCreate' 的后续调用将本地的 'StateSaverAndLoader' NBT 传递给 'StateSaverAndLoader::createFromNbt'
-        // 'StateSaverAndLoader' NBT on disk to our function 'StateSaverAndLoader::createFromNbt'.+
         StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID);         StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID);
  
-        // If state is not marked dirty, when Minecraft closes, 'writeNbt' won't be called and therefore nothing will be saved. +        // 若状态未标记为脏(dirty),当 Minecraft 关闭时, 'writeNbt' 不会被调用,相应地,没有数据会被保存。 
-        // Technically it's 'cleaner' if you only mark state as dirty when there was actually a change, but the vast majority +        // 从技术上讲,只有在事实上发生数据变更时才应当将状态标记为脏(dirty)。 
-        // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to 'markDirty' for them. +        // 但大多数开发者和模组作者会对他们的数据未能保存而感到困惑,所以不妨直接使用 'markDirty'  
-        // Besides, it's literally just setting a bool to true, and the only time there's a 'cost' is when the file is written to disk when +        // 另外,这只将对应的布尔值设定为 TRUE,代价是文件写入磁盘时模组的状态不会有任何改变。(这种情况非常少见)
-        // there were no actual change to any of the mods state (INCREDIBLY RARE).+
         state.markDirty();         state.markDirty();
  
Line 237: Line 235:
 </code> </code>
  
-You'll also have to update your class which ''**implements ModInitializer**'' so that it's as follows:+相应地,您也需要将实现了 ''**ModInitializer**'' 的类做如下改动:
  
 <code java> <code java>
Line 253: Line 251:
 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, "dirt_broken");     public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, "dirt_broken");
Line 262: Line 260:
             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 279:
 </code> </code>
  
-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.+如果您现在运行游戏,您会发现计数器正常递增,但现在即使您关闭游戏并重新启动,计数器也会从退出时的位置继续递增。 
 + 
 +有一点您有可能会忽略,''**totalDirtBlocksBroken**'' 不是玩家限定的,这意味着若这个模组运行在服务器侧,并同时有好几个玩家挖掘泥土方块,他们都会收到相同的统计数字。\\ 
 +这对我们模组中的特定类型数据是很好的,表明它们能正常工作。但更多时候,我们期望数据是玩家限定(因人而异)的。 
 +正如我们开篇所提,如果我们想要保留**任意玩家**的**特定方块**的挖掘数据,这时我们要怎么做?
  
-What you might or might not expect is that ''**totalDirtBlocksBroken**'' is not specific to a player, that is, if you made a server with this mod, and a few people were running around breaking dirt blocks, all of them would increment that same number. This is fine for certain types of data we'd like to store for our mods, but most of the time, we want to store player-specific data. For instance, as we mentioned at the start of this article, what if we would like to store how many dirt blocks any //specific// player has broken? 
 ====== Player Specific Persistent State ====== ====== Player Specific Persistent State ======
  
zh_cn/tutorial/persistent_states.txt · Last modified: 2023/12/23 02:39 by dreamuniverse