From 5f501a0e7e4427d3609eb71a584159c1199a7e7d Mon Sep 17 00:00:00 2001 From: KrisHD1337 Date: Wed, 11 Jun 2025 14:33:56 +0200 Subject: [PATCH] Add persistent storage for party inventories --- gradle.properties | 2 +- .../entity/StaliniumCacheBlockEntity.java | 32 ++++-- .../util/StaliniumPartyCacheData.java | 101 ++++++++++++++++++ 3 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/krituximon/stalinium/util/StaliniumPartyCacheData.java diff --git a/gradle.properties b/gradle.properties index 0116a56..509d351 100644 --- a/gradle.properties +++ b/gradle.properties @@ -36,7 +36,7 @@ mod_name=Stalinium # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=0.2.1 +mod_version=0.2.2 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/net/krituximon/stalinium/block/entity/StaliniumCacheBlockEntity.java b/src/main/java/net/krituximon/stalinium/block/entity/StaliniumCacheBlockEntity.java index a5f07c9..29d82b3 100644 --- a/src/main/java/net/krituximon/stalinium/block/entity/StaliniumCacheBlockEntity.java +++ b/src/main/java/net/krituximon/stalinium/block/entity/StaliniumCacheBlockEntity.java @@ -3,6 +3,7 @@ package net.krituximon.stalinium.block.entity; import net.krituximon.stalinium.event.ComradeHandler; +import net.krituximon.stalinium.util.StaliniumPartyCacheData; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.Registries; @@ -29,22 +30,39 @@ import java.util.concurrent.ConcurrentHashMap; public class StaliniumCacheBlockEntity extends BlockEntity { private static final int SIZE = 27; - private static final Map PARTY_INVENTORIES = new ConcurrentHashMap<>(); public StaliniumCacheBlockEntity(BlockPos pos, BlockState state) { super(ModBlockEntities.STALINIUM_CACHE_BE.get(), pos, state); } - + + /** + * Obtain – and create if necessary – the inventory that belongs to the player’s party. + */ public static SimpleContainer getPartyInventory(@Nullable Player who) { + UUID key; if (who == null) { - UUID defaultKey = UUID.randomUUID(); - return PARTY_INVENTORIES.computeIfAbsent(defaultKey, __ -> new SimpleContainer(SIZE)); + key = new UUID(0L, 0L); // world-wide default dump + } else { + Optional opt = ComradeHandler.findPartyOf(who.getUUID()); + key = opt.map(p -> p.leader).orElse(who.getUUID()); } - Optional opt = ComradeHandler.findPartyOf(who.getUUID()); - UUID key = opt.map(p -> p.leader).orElse(who.getUUID()); - return PARTY_INVENTORIES.computeIfAbsent(key, __ -> new SimpleContainer(SIZE)); + + // We keep the containers in the world-persistent SavedData + Level lvl = who != null ? who.level() : null; + if (lvl == null || lvl.isClientSide) // should never happen on the server + return new SimpleContainer(SIZE); + + StaliniumPartyCacheData data = StaliniumPartyCacheData.get(lvl); + return data.getOrCreate(key); } + /* ---------- helper to mark the SavedData dirty whenever the container changes ---------- */ + public static void markDirty(Level level, UUID key) { + if (level.isClientSide) return; + StaliniumPartyCacheData.get(level).setDirty(); + } + + // drop-logic unchanged … public void drops() { SimpleContainer inv = getPartyInventory(null); SimpleContainer tmp = new SimpleContainer(SIZE); diff --git a/src/main/java/net/krituximon/stalinium/util/StaliniumPartyCacheData.java b/src/main/java/net/krituximon/stalinium/util/StaliniumPartyCacheData.java new file mode 100644 index 0000000..fce82c8 --- /dev/null +++ b/src/main/java/net/krituximon/stalinium/util/StaliniumPartyCacheData.java @@ -0,0 +1,101 @@ +package net.krituximon.stalinium.util; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.*; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.SavedData; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * World-persistent store for every party’s cache inventory. + * Saved/loaded automatically by the game. + */ +public class StaliniumPartyCacheData extends SavedData { + private static final String DATA_NAME = "stalinium_party_caches"; + private static final int SIZE = 27; + + private final Map inventories = new HashMap<>(); + + /* ------------------------------------------------- */ + /* helper that produces an inventory wired to setDirty */ + /* ------------------------------------------------- */ + + private SimpleContainer newContainer() { + /* Every time the container changes, flag the data object. */ + return new SimpleContainer(SIZE) { + @Override + public void setChanged() { + super.setChanged(); + StaliniumPartyCacheData.this.setDirty(); + } + }; + } + + /* ---------------- public API ---------------- */ + + /** Get (or lazily create) the inventory for the given party / player. */ + public SimpleContainer getOrCreate(UUID id) { + return inventories.computeIfAbsent(id, __ -> newContainer()); + } + + /* ---------------- persistence ---------------- */ + + @Override + public CompoundTag save(CompoundTag tag, HolderLookup.Provider provider) { + ListTag list = new ListTag(); + + inventories.forEach((uuid, container) -> { + CompoundTag entry = new CompoundTag(); + entry.putUUID("Id", uuid); + + NonNullList tmp = + NonNullList.withSize(container.getContainerSize(), ItemStack.EMPTY); + for (int i = 0; i < container.getContainerSize(); ++i) { + tmp.set(i, container.getItem(i)); + } + ContainerHelper.saveAllItems(entry, tmp, provider); + list.add(entry); + }); + + tag.put("Inventories", list); + return tag; + } + + /** Deserializer – now also uses {@link #newContainer()} so the hook survives loading. */ + public static StaliniumPartyCacheData load(CompoundTag tag, HolderLookup.Provider provider) { + StaliniumPartyCacheData data = new StaliniumPartyCacheData(); + ListTag list = tag.getList("Inventories", Tag.TAG_COMPOUND); + + list.forEach(t -> { + CompoundTag entry = (CompoundTag) t; + UUID id = entry.getUUID("Id"); + + SimpleContainer cont = data.newContainer(); + NonNullList tmp = NonNullList.withSize(SIZE, ItemStack.EMPTY); + ContainerHelper.loadAllItems(entry, tmp, provider); + for (int i = 0; i < SIZE; ++i) cont.setItem(i, tmp.get(i)); + + data.inventories.put(id, cont); + }); + + return data; + } + + /* ---------------- factory / access ---------------- */ + + private static final SavedData.Factory FACTORY = + new SavedData.Factory<>(StaliniumPartyCacheData::new, StaliniumPartyCacheData::load); + + public static StaliniumPartyCacheData get(Level lvl) { + if (lvl.isClientSide) throw new IllegalStateException("Called on client"); + return ((ServerLevel) lvl).getDataStorage().computeIfAbsent(FACTORY, DATA_NAME); + } +} \ No newline at end of file