package wtf.hak.survivalfabric.features.sharedenderchest; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.block.Blocks; import net.minecraft.block.EnderChestBlock; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.Inventories; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.SimpleNamedScreenHandlerFactory; import net.minecraft.server.MinecraftServer; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.WorldSavePath; import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import java.io.*; import static wtf.hak.survivalfabric.SurvivalFabric.LOGGER; import static wtf.hak.survivalfabric.config.ConfigManager.getConfig; public class SharedEnderChest implements ServerLifecycleEvents.ServerStopping, ServerLifecycleEvents.ServerStarted, ServerTickEvents.EndTick { private static SharedInventory sharedInventory; private long ticksUntilSave = -20; public static void saveInventory(MinecraftServer server) { File inventoryFile = getFile(server); NbtCompound nbt = new NbtCompound(); DefaultedList inventoryItemStacks = DefaultedList.ofSize(getConfig().sharedEnderChestRows * 9, ItemStack.EMPTY); Inventories.writeNbt(nbt, sharedInventory.getList(inventoryItemStacks), server.getRegistryManager()); try (FileOutputStream inventoryFileOutputStream = new FileOutputStream(inventoryFile); DataOutputStream inventoryFileDataOutput = new DataOutputStream(inventoryFileOutputStream)) { inventoryFile.createNewFile(); NbtIo.writeCompressed(nbt, inventoryFileDataOutput); } catch (Exception e) { LOGGER.error("Error while saving Shared Ender Chest: " + e); } } public static void openSharedEnderChest(PlayerEntity player, World world, BlockPos pos) { fakeEnderChestOpen(world, pos, true); sharedInventory.openedEnderChests.put(player, pos); player.openHandledScreen(new SimpleNamedScreenHandlerFactory((int_1, playerInventory, playerEntity) -> new GenericContainerScreenHandler(getConfig().screenHandlerType(), int_1, playerInventory, sharedInventory, getConfig().sharedEnderChestRows), Text.of(getConfig().sharedEnderChestName))); } public static void playEnderChestOpenSound(World world, BlockPos pos) { world.playSound(null, pos, SoundEvents.BLOCK_ENDER_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); } public static void playEnderChestCloseSound(World world, BlockPos pos) { world.playSound(null, pos, SoundEvents.BLOCK_ENDER_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); } public static void fakeEnderChestOpen(World world, BlockPos pos, boolean open) { if (!(world.getBlockState(pos).getBlock() instanceof EnderChestBlock)) { return; } if (open) playEnderChestOpenSound(world, pos); else playEnderChestCloseSound(world, pos); world.addSyncedBlockEvent(pos, Blocks.ENDER_CHEST, 1, open ? 1 : 0); } private static File getFile(MinecraftServer server) { return server.getSavePath(WorldSavePath.ROOT).resolve("sharedenderchest.sav").toFile(); } public void onServerStarted(MinecraftServer server) { File inventoryFile = getFile(server); if (inventoryFile.exists()) { try (FileInputStream inventoryFileInputStream = new FileInputStream(inventoryFile); DataInputStream inventoryFileDataInput = new DataInputStream(inventoryFileInputStream)) { NbtCompound nbt = NbtIo.readCompressed(inventoryFileDataInput, NbtSizeTracker.ofUnlimitedBytes()); DefaultedList inventoryItemStacks = DefaultedList.ofSize(getConfig().sharedEnderChestRows * 9, ItemStack.EMPTY); Inventories.readNbt(nbt, inventoryItemStacks, server.getRegistryManager()); sharedInventory = new SharedInventory(inventoryItemStacks); } catch (Exception e) { LOGGER.error("Error while loading Shared Ender Chest: " + e); sharedInventory = new SharedInventory(getConfig().sharedEnderChestRows); } } else { sharedInventory = new SharedInventory(getConfig().sharedEnderChestRows); } } public void onServerStopping(MinecraftServer server) { saveInventory(server); } public void onEndTick(MinecraftServer server) { if (ticksUntilSave != -20 && --ticksUntilSave <= 0L) { saveInventory(server); ticksUntilSave = 20L; } } public void onInitialize() { ticksUntilSave = 20L; UseBlockCallback listenerUseBlock = (player, world, hand, hitResult) -> { if (world.getBlockState(hitResult.getBlockPos()).getBlock() instanceof EnderChestBlock) { if (!player.isSpectator()) { if (!getConfig().sharedEnderChestLimitedAccess) { if (world.isClient()) return ActionResult.SUCCESS; openSharedEnderChest(player, world, hitResult.getBlockPos()); return ActionResult.SUCCESS; } else { for (String name : getConfig().sharedEnderChestNames) { if (name.toLowerCase().strip().equalsIgnoreCase(player.getNameForScoreboard().toLowerCase())) { if (world.isClient()) return ActionResult.SUCCESS; openSharedEnderChest(player, world, hitResult.getBlockPos()); return ActionResult.SUCCESS; } } } } } return ActionResult.PASS; }; UseBlockCallback.EVENT.register(listenerUseBlock); ServerLifecycleEvents.SERVER_STARTED.register(this); ServerLifecycleEvents.SERVER_STOPPING.register(this); ServerTickEvents.END_SERVER_TICK.register(this); } }