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 [2024/01/11 06:44] – typo jmanc3 | tutorial:persistent_states [2025/03/13 14:52] (current) – world.getServer() only once, harmonized MOD_ID lakazatong | ||
---|---|---|---|
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 110: | Line 130: | ||
@Override | @Override | ||
- | public NbtCompound writeNbt(NbtCompound nbt) { | + | public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { |
nbt.putInt(" | nbt.putInt(" | ||
return nbt; | return nbt; | ||
Line 121: | Line 141: | ||
* '' | * '' | ||
- | Next add the following | + | Next add the following |
<code java> | <code java> | ||
Line 128: | Line 148: | ||
// ... (Previously written code) | // ... (Previously written code) | ||
- | 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(" | ||
+ | return state; | ||
+ | } | ||
+ | |||
+ | public static StateSaverAndLoader createNew() { | ||
+ | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
+ | state.totalDirtBlocksBroken = 0; | ||
return state; | return state; | ||
} | } | ||
Line 136: | Line 162: | ||
</ | </ | ||
- | This function does the opposite of '' | + | First function does the opposite of '' |
* Note: how we pull out the int we stored earlier with '' | * 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 '' | + | Second function refreshing variables '' |
+ | |||
+ | 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 175: | ||
// ... (Previously written code) | // ... (Previously written code) | ||
- | private static Type< | + | private static |
- | StateSaverAndLoader:: | + | StateSaverAndLoader:: |
StateSaverAndLoader:: | StateSaverAndLoader:: | ||
null // Supposed to be an ' | null // Supposed to be an ' | ||
Line 155: | Line 183: | ||
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, | + | StateSaverAndLoader state = serverWorld.getPersistentStateManager().getOrCreate(type, |
// If state is not marked dirty, when Minecraft closes, ' | // If state is not marked dirty, when Minecraft closes, ' | ||
Line 178: | Line 207: | ||
<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 188: | Line 218: | ||
@Override | @Override | ||
- | public NbtCompound writeNbt(NbtCompound nbt) { | + | public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { |
nbt.putInt(" | nbt.putInt(" | ||
return nbt; | return nbt; | ||
} | } | ||
- | 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 199: | Line 229: | ||
} | } | ||
- | private static Type< | + | |
- | StateSaverAndLoader:: | + | StateSaverAndLoader state = new StateSaverAndLoader(); |
+ | state.totalDirtBlocksBroken = 0; | ||
+ | return state; | ||
+ | } | ||
+ | |||
+ | | ||
+ | StateSaverAndLoader:: | ||
StateSaverAndLoader:: | StateSaverAndLoader:: | ||
null // Supposed to be an ' | null // Supposed to be an ' | ||
Line 207: | Line 243: | ||
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, | + | StateSaverAndLoader state = serverWorld.getPersistentStateManager().getOrCreate(type, |
// If state is not marked dirty, when Minecraft closes, ' | // If state is not marked dirty, when Minecraft closes, ' | ||
Line 231: | Line 268: | ||
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 346: | Line 378: | ||
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 386: | ||
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 396: | ||
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 435: | ||
</ | </ | ||
- | 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 461: | ||
} | } | ||
- | 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 475: | ||
}); | }); | ||
+ | return state; | ||
+ | } | ||
+ | | ||
+ | public static StateSaverAndLoader createNew() { | ||
+ | StateSaverAndLoader state = new StateSaverAndLoader(); | ||
+ | state.totalDirtBlocksBroken = 0; | ||
+ | state.players = new HashMap<> | ||
return state; | return state; | ||
} | } | ||
Line 486: | Line 526: | ||
} | } | ||
- | 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 540: | ||
}); | }); | ||
+ | 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 567: | Line 614: | ||
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 586: | Line 633: | ||
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 592: | Line 643: | ||
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 714: | Line 762: | ||
} | } | ||
- | 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 739: | Line 787: | ||
}); | }); | ||
+ | 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 827: | Line 882: | ||
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 846: | Line 901: | ||
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 852: | Line 911: | ||
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.1704955448.txt.gz · Last modified: 2024/01/11 06:44 by jmanc3