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 [2025/03/12 16:59] – fixed the "Simple Message" code to work with "fabricloader": ">=0.16.10" and "minecraft": "~1.21.4" lakazatong | tutorial:persistent_states [2025/07/28 20:33] (current) – Begin update to 1.21.5 the...why...even...how | ||
---|---|---|---|
Line 64: | Line 64: | ||
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) { | ||
- | | + | |
MinecraftServer server = world.getServer(); | MinecraftServer server = world.getServer(); | ||
- | |||
assert server != null; | assert server != null; | ||
+ | |||
+ | // Increment the amount of dirt blocks that have been broken | ||
+ | totalDirtBlocksBroken += 1; | ||
+ | |||
ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ServerPlayerEntity playerEntity = server.getPlayerManager().getPlayer(player.getUuid()); | ||
server.execute(() -> { | server.execute(() -> { | ||
Line 91: | Line 93: | ||
import net.minecraft.text.Text; | import net.minecraft.text.Text; | ||
- | public class PCBModClient | + | public class ExampleModClient |
private static void handleDirtBrokenPayload(DirtBrokenPayload payload, ClientPlayNetworking.Context context) { | private static void handleDirtBrokenPayload(DirtBrokenPayload payload, ClientPlayNetworking.Context context) { | ||
ClientPlayerEntity player = context.client().player; | ClientPlayerEntity player = context.client().player; | ||
Line 100: | Line 102: | ||
@Override | @Override | ||
public void onInitializeClient() { | public void onInitializeClient() { | ||
- | ClientPlayNetworking.registerGlobalReceiver(DirtBrokenPayload.ID, | + | ClientPlayNetworking.registerGlobalReceiver(DirtBrokenPayload.ID, |
} | } | ||
} | } | ||
Line 117: | 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 125: | 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 functions to that same file: | + | |
<code java> | <code java> | ||
Line 145: | Line 140: | ||
// ... (Previously written code) | // ... (Previously written code) | ||
- | | + | |
- | StateSaverAndLoader state = new StateSaverAndLoader(); | + | |
- | state.totalDirtBlocksBroken = tag.getInt(" | + | |
- | return state; | + | |
} | } | ||
- | | + | |
- | | + | |
- | | + | |
- | state.totalDirtBlocksBroken = 0; | + | |
- | return state; | + | |
} | } | ||
+ | |||
+ | private int getTotalDirtBlocksBroken() { | ||
+ | return totalDirtBlocksBroken; | ||
+ | } | ||
+ | |||
+ | private static final Codec< | ||
+ | StateSaverAndLoader:: | ||
+ | StateSaverAndLoader:: | ||
+ | ); | ||
} | } | ||
</ | </ | ||
- | |||
- | First function does the opposite of '' | ||
- | |||
- | * Note: how we pull out the int we stored earlier with '' | ||
- | |||
- | Second function refreshing variables '' | ||
- | |||
Now we just need to add one more utility function which hooks everything up together. This function will take a '' | Now we just need to add one more utility function which hooks everything up together. This function will take a '' | ||
Line 172: | 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 180: | 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 202: | 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 212: | Line 208: | ||
public Integer totalDirtBlocksBroken = 0; | public Integer totalDirtBlocksBroken = 0; | ||
- | | + | |
- | public NbtCompound writeNbt(NbtCompound nbt) { | + | |
- | nbt.putInt(" | + | |
- | return nbt; | + | |
} | } | ||
- | | + | |
- | | + | |
- | state.totalDirtBlocksBroken = tag.getInt(" | + | |
- | return state; | + | |
} | } | ||
- | | + | |
- | | + | |
- | | + | |
- | state.totalDirtBlocksBroken | + | |
- | return state; | + | |
} | } | ||
- | 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 238: | 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 262: | 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 377: | 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 385: | 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 391: | 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 612: | 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 631: | 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 637: | 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 879: | 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 898: | 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 904: | 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.1741798780.txt.gz · Last modified: 2025/03/12 16:59 by lakazatong