tutorial:persistent_states
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tutorial:persistent_states [2023/09/28 05:52] – Dropped un-needed DataFixType parameter and made type singleton jmanc3 | tutorial:persistent_states [2025/11/18 03:33] (current) – cassiancc | ||
|---|---|---|---|
| Line 19: | Line 19: | ||
| First, since the data will be saved on the ' | First, since the data will be saved on the ' | ||
| - | Modify | + | For that, we need to define a Payload which '' |
| + | |||
| + | <code java> | ||
| + | import net.minecraft.network.PacketByteBuf; | ||
| + | import net.minecraft.network.codec.PacketCodec; | ||
| + | import net.minecraft.network.codec.PacketCodecs; | ||
| + | import net.minecraft.network.packet.CustomPayload; | ||
| + | import net.minecraft.util.Identifier; | ||
| + | |||
| + | public record DirtBrokenPayload(Integer totalDirtBlocksBroken) implements CustomPayload { | ||
| + | public static final Identifier DIRT_BROKEN_ID = Identifier.of(MOD_ID, | ||
| + | public static final CustomPayload.Id< | ||
| + | public static final PacketCodec< | ||
| + | PacketCodecs.INTEGER, | ||
| + | DirtBrokenPayload:: | ||
| + | |||
| + | @Override | ||
| + | public Id<? extends CustomPayload> | ||
| + | return ID; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Next, modify | ||
| <code java> | <code java> | ||
| import net.fabricmc.api.ModInitializer; | import net.fabricmc.api.ModInitializer; | ||
| import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; | import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; | ||
| - | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; | + | import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; |
| - | import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; | + | |
| import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; | ||
| import net.minecraft.block.Blocks; | import net.minecraft.block.Blocks; | ||
| - | import net.minecraft.network.PacketByteBuf; | ||
| import net.minecraft.server.MinecraftServer; | import net.minecraft.server.MinecraftServer; | ||
| import net.minecraft.server.network.ServerPlayerEntity; | import net.minecraft.server.network.ServerPlayerEntity; | ||
| - | import net.minecraft.util.Identifier; | ||
| 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 = "examplemod"; |
| - | + | ||
| - | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | + | |
| private Integer totalDirtBlocksBroken = 0; | private Integer totalDirtBlocksBroken = 0; | ||
| - | @Override | ||
| public void onInitialize() { | public void onInitialize() { | ||
| + | PayloadTypeRegistry.playS2C().register(DirtBrokenPayload.ID, | ||
| + | |||
| 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) { | ||
| - | // Increment the amount of dirt blocks that have been broken | ||
| - | totalDirtBlocksBroken += 1; | ||
| - | |||
| // Send a packet to the client | // Send a packet to the client | ||
| MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
| + | assert server != null; | ||
| - | | + | |
| - | | + | totalDirtBlocksBroken |
| ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ||
| server.execute(() -> { | server.execute(() -> { | ||
| - | ServerPlayNetworking.send(playerEntity, | + | |
| + | | ||
| }); | }); | ||
| } | } | ||
| Line 67: | Line 85: | ||
| * To send a packet we use: '' | * To send a packet we use: '' | ||
| - | Next modify your class which '' | + | Finally, |
| <code java> | <code java> | ||
| import net.fabricmc.api.ClientModInitializer; | import net.fabricmc.api.ClientModInitializer; | ||
| import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; | ||
| - | import net.minecraft.text.Text; | + | import net.minecraft.client.network.ClientPlayerEntity; |
| + | import net.minecraft.text.Text; | ||
| public class ExampleModClient implements ClientModInitializer { | public class ExampleModClient implements ClientModInitializer { | ||
| + | private static void handleDirtBrokenPayload(DirtBrokenPayload payload, ClientPlayNetworking.Context context) { | ||
| + | ClientPlayerEntity player = context.client().player; | ||
| + | assert player != null; | ||
| + | player.sendMessage(Text.literal(" | ||
| + | } | ||
| @Override | @Override | ||
| public void onInitializeClient() { | public void onInitializeClient() { | ||
| - | ClientPlayNetworking.registerGlobalReceiver(ExampleMod.DIRT_BROKEN, (client, handler, buf, responseSender) -> { | + | ClientPlayNetworking.registerGlobalReceiver(DirtBrokenPayload.ID, ExampleModClient: |
| - | int totalDirtBlocksBroken = buf.readInt(); | + | |
| - | client.execute(() -> { | + | |
| - | client.player.sendMessage(Text.literal(" | + | |
| - | }); | + | |
| - | }); | + | |
| } | } | ||
| } | } | ||
| Line 100: | Line 119: | ||
| <code java> | <code java> | ||
| import net.minecraft.nbt.NbtCompound; | import net.minecraft.nbt.NbtCompound; | ||
| + | import net.minecraft.registry.RegistryWrapper; | ||
| import net.minecraft.server.MinecraftServer; | import net.minecraft.server.MinecraftServer; | ||
| + | import net.minecraft.server.world.ServerWorld; | ||
| import net.minecraft.world.PersistentState; | import net.minecraft.world.PersistentState; | ||
| - | import net.minecraft.world.PersistentStateManager; | ||
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||
| Line 108: | Line 128: | ||
| public Integer totalDirtBlocksBroken = 0; | public Integer totalDirtBlocksBroken = 0; | ||
| - | |||
| - | @Override | ||
| - | public NbtCompound writeNbt(NbtCompound nbt) { | ||
| - | nbt.putInt(" | ||
| - | return nbt; | ||
| - | } | ||
| } | } | ||
| </ | </ | ||
| - | Note: '' | + | Note: |
| - | | + | - |
| - | + | ||
| - | Next add the following function to that same file: | + | |
| <code java> | <code java> | ||
| Line 128: | Line 140: | ||
| // ... (Previously written code) | // ... (Previously written code) | ||
| - | | + | |
| - | StateSaverAndLoader state = new StateSaverAndLoader(); | + | |
| - | state.totalDirtBlocksBroken = tag.getInt(" | + | |
| - | return state; | + | |
| } | } | ||
| + | |||
| + | private StateSaverAndLoader(int totalDirtBlocksBroken) { | ||
| + | this.totalDirtBlocksBroken = totalDirtBlocksBroken; | ||
| + | } | ||
| + | |||
| + | private int getTotalDirtBlocksBroken() { | ||
| + | return totalDirtBlocksBroken; | ||
| + | } | ||
| + | |||
| + | private static final Codec< | ||
| + | StateSaverAndLoader:: | ||
| + | StateSaverAndLoader:: | ||
| + | ); | ||
| } | } | ||
| </ | </ | ||
| - | + | Now we just need to add one more utility function which hooks everything up together. This function will take a '' | |
| - | 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> | ||
| Line 147: | Line 164: | ||
| // ... (Previously written code) | // ... (Previously written code) | ||
| - | private static | + | private static |
| - | StateSaverAndLoader:: | + | (String) ExampleMod.MOD_ID, |
| - | | + | StateSaverAndLoader:: |
| + | | ||
| null // Supposed to be an ' | null // Supposed to be an ' | ||
| ); | ); | ||
| Line 155: | Line 173: | ||
| public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
| // (Note: arbitrary choice to use ' | // (Note: arbitrary choice to use ' | ||
| - | | + | |
| + | assert serverWorld != null; | ||
| // The first time the following ' | // The first time the following ' | ||
| // stores it inside the ' | // stores it inside the ' | ||
| - | // ' | + | // ' |
| - | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID); | + | StateSaverAndLoader state = serverWorld.getPersistentStateManager().getOrCreate(type); |
| - | // If state is not marked dirty, | + | // If state is not marked dirty, nothing will be saved when Minecraft closes. |
| // Technically it's ' | // Technically it's ' | ||
| // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | ||
| Line 177: | Line 196: | ||
| <code java> | <code java> | ||
| - | import | + | import |
| import net.minecraft.server.MinecraftServer; | import net.minecraft.server.MinecraftServer; | ||
| + | import net.minecraft.server.world.ServerWorld; | ||
| import net.minecraft.world.PersistentState; | import net.minecraft.world.PersistentState; | ||
| - | import net.minecraft.world.PersistentStateManager; | + | import net.minecraft.world.PersistentStateType; |
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||
| Line 187: | Line 208: | ||
| public Integer totalDirtBlocksBroken = 0; | public Integer totalDirtBlocksBroken = 0; | ||
| - | | + | |
| - | public NbtCompound writeNbt(NbtCompound nbt) { | + | |
| - | nbt.putInt(" | + | |
| - | return nbt; | + | |
| } | } | ||
| - | | + | |
| - | | + | |
| - | state.totalDirtBlocksBroken = tag.getInt(" | + | } |
| - | return | + | |
| + | private int getTotalDirtBlocksBroken() { | ||
| + | return | ||
| } | } | ||
| - | private static | + | private static |
| - | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
| - | | + | StateSaverAndLoader:: |
| + | ); | ||
| + | |||
| + | private static final PersistentStateType< | ||
| + | (String) ExampleMod.MOD_ID, | ||
| + | StateSaverAndLoader:: | ||
| + | | ||
| null // Supposed to be an ' | null // Supposed to be an ' | ||
| ); | ); | ||
| Line 207: | Line 233: | ||
| public static StateSaverAndLoader getServerState(MinecraftServer server) { | public static StateSaverAndLoader getServerState(MinecraftServer server) { | ||
| // (Note: arbitrary choice to use ' | // (Note: arbitrary choice to use ' | ||
| - | | + | |
| + | assert serverWorld != null; | ||
| // The first time the following ' | // The first time the following ' | ||
| // stores it inside the ' | // stores it inside the ' | ||
| - | // ' | + | // ' |
| - | StateSaverAndLoader state = persistentStateManager.getOrCreate(type, ExampleMod.MOD_ID); | + | StateSaverAndLoader state = serverWorld.getPersistentStateManager().getOrCreate(type); |
| - | // If state is not marked dirty, | + | // If state is not marked dirty, nothing will be saved when Minecraft closes. |
| // Technically it's ' | // Technically it's ' | ||
| // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | // of mod writers are just going to be confused when their data isn't being saved, and so it's best just to ' | ||
| Line 231: | Line 258: | ||
| import net.fabricmc.api.ModInitializer; | import net.fabricmc.api.ModInitializer; | ||
| import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; | import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; | ||
| - | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; | + | import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; |
| - | import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; | + | |
| import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; | ||
| import net.minecraft.block.Blocks; | import net.minecraft.block.Blocks; | ||
| - | import net.minecraft.network.PacketByteBuf; | ||
| import net.minecraft.server.MinecraftServer; | import net.minecraft.server.MinecraftServer; | ||
| import net.minecraft.server.network.ServerPlayerEntity; | import net.minecraft.server.network.ServerPlayerEntity; | ||
| - | import net.minecraft.util.Identifier; | ||
| 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 = "examplemod"; |
| - | public | + | public |
| + | PayloadTypeRegistry.playS2C().register(DirtBrokenPayload.ID, DirtBrokenPayload.CODEC); | ||
| - | @Override | ||
| - | 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()); | ||
| - | // Increment the amount of dirt blocks that have been broken | ||
| - | serverState.totalDirtBlocksBroken += 1; | ||
| - | |||
| // Send a packet to the client | // Send a packet to the client | ||
| MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
| + | assert server != null; | ||
| - | | + | |
| - | | + | StateSaverAndLoader serverState |
| + | serverState.totalDirtBlocksBroken | ||
| ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ||
| server.execute(() -> { | server.execute(() -> { | ||
| - | ServerPlayNetworking.send(playerEntity, | + | |
| + | | ||
| }); | }); | ||
| } | } | ||
| Line 307: | Line 329: | ||
| </ | </ | ||
| - | Note: We create a '' | + | Note: We create a '' |
| Let's add a utility function to '' | Let's add a utility function to '' | ||
| Line 346: | Line 368: | ||
| 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 = "examplemod"; |
| public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
| Line 354: | Line 376: | ||
| 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()); | + | |
| + | MinecraftServer server = world.getServer(); | ||
| + | assert server != null; | ||
| + | |||
| + | | ||
| // Increment the amount of dirt blocks that have been broken | // Increment the amount of dirt blocks that have been broken | ||
| serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
| Line 360: | Line 386: | ||
| PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | ||
| playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
| - | |||
| - | // Send a packet to the client | ||
| - | MinecraftServer server = world.getServer(); | ||
| PacketByteBuf data = PacketByteBufs.create(); | PacketByteBuf data = PacketByteBufs.create(); | ||
| Line 402: | Line 425: | ||
| </ | </ | ||
| - | If you ran the client now, it would seem as if everything is working, but we are forgetting a crucial step: We haven' | + | 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: | The updated functions are as follows: | ||
| Line 428: | Line 451: | ||
| } | } | ||
| - | public static StateSaverAndLoader createFromNbt(NbtCompound tag) { | + | public static StateSaverAndLoader createFromNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { |
| StateSaverAndLoader state = new StateSaverAndLoader(); | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| state.totalDirtBlocksBroken = tag.getInt(" | state.totalDirtBlocksBroken = tag.getInt(" | ||
| Line 442: | Line 465: | ||
| }); | }); | ||
| + | return state; | ||
| + | } | ||
| + | | ||
| + | public static StateSaverAndLoader createNew() { | ||
| + | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| + | state.totalDirtBlocksBroken = 0; | ||
| + | state.players = new HashMap<> | ||
| return state; | return state; | ||
| } | } | ||
| Line 486: | Line 516: | ||
| } | } | ||
| - | public static StateSaverAndLoader createFromNbt(NbtCompound tag) { | + | public static StateSaverAndLoader createFromNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { |
| StateSaverAndLoader state = new StateSaverAndLoader(); | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| state.totalDirtBlocksBroken = tag.getInt(" | state.totalDirtBlocksBroken = tag.getInt(" | ||
| Line 500: | Line 530: | ||
| }); | }); | ||
| + | return state; | ||
| + | } | ||
| + | | ||
| + | public static StateSaverAndLoader createNew() { | ||
| + | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| + | state.totalDirtBlocksBroken = 0; | ||
| + | state.players = new HashMap<> | ||
| return state; | return state; | ||
| } | } | ||
| private static Type< | private static Type< | ||
| - | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
| StateSaverAndLoader:: | StateSaverAndLoader:: | ||
| null // Supposed to be an ' | null // Supposed to be an ' | ||
| Line 541: | Line 578: | ||
| Running the client now, all our player-specific data is correctly saved. | Running the client now, all our player-specific data is correctly saved. | ||
| - | | + | ==== Important Caveat ==== |
| + | |||
| + | | ||
| Just remember if you add new fields to '' | Just remember if you add new fields to '' | ||
| Line 565: | Line 604: | ||
| 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 = "examplemod"; |
| public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
| Line 584: | Line 623: | ||
| 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()); | + | |
| + | MinecraftServer server = world.getServer(); | ||
| + | assert server != null; | ||
| + | |||
| + | | ||
| // Increment the amount of dirt blocks that have been broken | // Increment the amount of dirt blocks that have been broken | ||
| serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
| Line 590: | Line 633: | ||
| PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | ||
| playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
| - | |||
| - | // Send a packet to the client | ||
| - | MinecraftServer server = world.getServer(); | ||
| PacketByteBuf data = PacketByteBufs.create(); | PacketByteBuf data = PacketByteBufs.create(); | ||
| Line 646: | Line 686: | ||
| * Note: The '' | * Note: The '' | ||
| - | | + | ==== Important Caveat ==== |
| + | |||
| + | | ||
| ====== More Involved Player Data ====== | ====== More Involved Player Data ====== | ||
| Line 710: | Line 752: | ||
| } | } | ||
| - | public static StateSaverAndLoader createFromNbt(NbtCompound tag) { | + | public static StateSaverAndLoader createFromNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { |
| StateSaverAndLoader state = new StateSaverAndLoader(); | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| state.totalDirtBlocksBroken = tag.getInt(" | state.totalDirtBlocksBroken = tag.getInt(" | ||
| Line 735: | Line 777: | ||
| }); | }); | ||
| + | return state; | ||
| + | } | ||
| + | | ||
| + | public static StateSaverAndLoader createNew() { | ||
| + | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
| + | state.totalDirtBlocksBroken = 0; | ||
| + | state.players = new HashMap<> | ||
| return state; | return state; | ||
| } | } | ||
| private static Type< | private static Type< | ||
| - | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
| StateSaverAndLoader:: | StateSaverAndLoader:: | ||
| null // Supposed to be an ' | null // Supposed to be an ' | ||
| Line 823: | Line 872: | ||
| 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 = "examplemod"; |
| public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | public static final Identifier DIRT_BROKEN = new Identifier(MOD_ID, | ||
| Line 842: | Line 891: | ||
| 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()); | + | |
| + | MinecraftServer server = world.getServer(); | ||
| + | assert server != null; | ||
| + | |||
| + | | ||
| // Increment the amount of dirt blocks that have been broken | // Increment the amount of dirt blocks that have been broken | ||
| serverState.totalDirtBlocksBroken += 1; | serverState.totalDirtBlocksBroken += 1; | ||
| Line 848: | Line 901: | ||
| PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | PlayerData playerState = StateSaverAndLoader.getPlayerState(player); | ||
| playerState.dirtBlocksBroken += 1; | playerState.dirtBlocksBroken += 1; | ||
| - | |||
| - | // Send a packet to the client | ||
| - | MinecraftServer server = world.getServer(); | ||
| PacketByteBuf data = PacketByteBufs.create(); | PacketByteBuf data = PacketByteBufs.create(); | ||
tutorial/persistent_states.1695880372.txt.gz · Last modified: 2023/09/28 05:52 by jmanc3