Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
java-version: 21
java-version: 25
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 21
java-version: 25

- name: Make gradlew executable
run: chmod +x ./gradlew
Expand Down
15 changes: 7 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '1.14-SNAPSHOT'
id 'net.fabricmc.fabric-loom' version "${loom_version}"
id 'maven-publish'
}

Expand Down Expand Up @@ -38,16 +38,15 @@ base {
dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
implementation "net.fabricmc:fabric-loader:${project.loader_version}"

// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"

// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
modImplementation include("eu.pb4:sgui:${project.sgui_version}")
modImplementation include("me.lucko:fabric-permissions-api:${project.permission_api_version}")
implementation include("eu.pb4:sgui:${project.sgui_version}")
implementation include("me.lucko:fabric-permissions-api:${project.permission_api_version}")

// modImplementation "dev.emi:trinkets:${project.trinkets_version}"
// modImplementation "com.github.apace100:apoli:${project.apoli_version}"
Expand All @@ -74,8 +73,8 @@ tasks.withType(JavaCompile) {
}

java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
}

jar {
Expand Down
12 changes: 6 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/develop/
minecraft_version=1.21.11
yarn_mappings=1.21.11+build.3
loader_version=0.18.3
minecraft_version=26.1
loader_version=0.18.5
loom_version=1.15-SNAPSHOT
# Mod Properties
mod_version=1.4.19
maven_group=us.potatoboy
archives_base_name=InvView
# Dependencies
# check this on https://fabricmc.net/develop/
fabric_version=0.140.0+1.21.11
fabric_version=0.144.3+26.1
# trinkets_version=3.10.0
# apoli_version=2.12.0
sgui_version=1.11.0+1.21.9
permission_api_version=0.6.1
sgui_version=2.0.0-beta.2+26.1
permission_api_version=0.7.0
47 changes: 23 additions & 24 deletions src/main/java/us/potatoboy/invview/InvView.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.command.argument.GameProfileArgumentType;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.GameProfileArgument;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.storage.NbtWriteView;
import net.minecraft.util.ErrorReporter;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.util.Util;
import net.minecraft.util.WorldSavePath;

import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.world.level.storage.TagValueOutput;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -38,22 +37,22 @@ public void onInitialize() {

CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {

LiteralCommandNode<ServerCommandSource> viewNode = CommandManager
LiteralCommandNode<CommandSourceStack> viewNode = Commands
.literal("view")
.requires(Permissions.require("invview.command.root", 2))
.build();

LiteralCommandNode<ServerCommandSource> invNode = CommandManager
LiteralCommandNode<CommandSourceStack> invNode = Commands
.literal("inv")
.requires(Permissions.require("invview.command.inv", 2))
.then(CommandManager.argument("target", GameProfileArgumentType.gameProfile())
.then(Commands.argument("target", GameProfileArgument.gameProfile())
.executes(ViewCommand::inv))
.build();

LiteralCommandNode<ServerCommandSource> echestNode = CommandManager
LiteralCommandNode<CommandSourceStack> echestNode = Commands
.literal("echest")
.requires(Permissions.require("invview.command.echest", 2))
.then(CommandManager.argument("target", GameProfileArgumentType.gameProfile())
.then(Commands.argument("target", GameProfileArgument.gameProfile())
.executes(ViewCommand::eChest))
.build();

Expand Down Expand Up @@ -95,18 +94,18 @@ public static MinecraftServer getMinecraftServer() {
}

// Taken from net.minecraft.world.PlayerSaveHandler.savePlayerData(), which is a protected method
public static void savePlayerData(ServerPlayerEntity player) {
File playerDataDir = minecraftServer.getSavePath(WorldSavePath.PLAYERDATA).toFile();
try (ErrorReporter.Logging logging = new ErrorReporter.Logging(player.getErrorReporterContext(), LogUtils.getLogger())) {
NbtWriteView nbtWriteView = NbtWriteView.create(logging, player.getRegistryManager());
player.writeData(nbtWriteView);
public static void savePlayerData(ServerPlayer player) {
File playerDataDir = minecraftServer.getWorldPath(LevelResource.PLAYER_DATA_DIR).toFile();
try (ProblemReporter.ScopedCollector logging = new ProblemReporter.ScopedCollector(player.problemPath(), LogUtils.getLogger())) {
TagValueOutput nbtWriteView = TagValueOutput.createWithContext(logging, player.registryAccess());
player.saveWithoutId(nbtWriteView);
Path path = playerDataDir.toPath();
Path path2 = Files.createTempFile(path, player.getUuidAsString() + "-", ".dat");
NbtCompound nbtCompound = nbtWriteView.getNbt();
Path path2 = Files.createTempFile(path, player.getStringUUID() + "-", ".dat");
CompoundTag nbtCompound = nbtWriteView.buildResult();
NbtIo.writeCompressed(nbtCompound, path2);
Path path3 = path.resolve(player.getUuidAsString() + ".dat");
Path path4 = path.resolve(player.getUuidAsString() + ".dat_old");
Util.backupAndReplace(path3, path2, path4);
Path path3 = path.resolve(player.getStringUUID() + ".dat");
Path path4 = path.resolve(player.getStringUUID() + ".dat_old");
Util.safeReplaceFile(path3, path2, path4);
} catch (Exception var11) {
LogUtils.getLogger().warn("Failed to save player data for {}", player.getName().getString());
}
Expand Down
108 changes: 54 additions & 54 deletions src/main/java/us/potatoboy/invview/ViewCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.command.argument.GameProfileArgumentType;
import net.minecraft.inventory.EnderChestInventory;
import net.minecraft.item.Items;
import net.minecraft.network.packet.c2s.common.SyncedClientOptions;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.Slot;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.GameProfileArgument;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerConfigEntry;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.storage.NbtReadView;
import net.minecraft.storage.ReadView;
import net.minecraft.text.Text;
import net.minecraft.util.ErrorReporter;
import net.minecraft.util.Identifier;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.NameAndId;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.PlayerEnderChestContainer;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.ValueInput;
import us.potatoboy.invview.gui.SavingPlayerDataGui;
import us.potatoboy.invview.gui.UnmodifiableSlot;
import us.potatoboy.invview.mixin.EntityAccessor;
Expand All @@ -38,21 +38,21 @@ public class ViewCommand {
private static final String permModify = "invview.can_modify";
private static final String msgProtected = "Requested inventory is protected";

public static int inv(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
ServerPlayerEntity player = context.getSource().getPlayer();
ServerPlayerEntity requestedPlayer = getRequestedPlayer(context);
public static int inv(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
ServerPlayer player = context.getSource().getPlayer();
ServerPlayer requestedPlayer = getRequestedPlayer(context);

boolean canModify = Permissions.check(context.getSource(), permModify, true);

Permissions.check(requestedPlayer.getUuid(), permProtected, false).thenAcceptAsync(isProtected -> {
Permissions.check(requestedPlayer.getUUID(), permProtected, false).thenAcceptAsync(isProtected -> {
if (isProtected) {
context.getSource().sendError(Text.literal(msgProtected));
context.getSource().sendFailure(Component.literal(msgProtected));
} else {
SimpleGui gui = new SavingPlayerDataGui(ScreenHandlerType.GENERIC_9X5, player, requestedPlayer);
SimpleGui gui = new SavingPlayerDataGui(MenuType.GENERIC_9x5, player, requestedPlayer);
gui.setTitle(requestedPlayer.getName());
addBackground(gui);
for (int i = 0; i < requestedPlayer.getInventory().size(); i++) {
gui.setSlotRedirect(i, canModify ? new Slot(requestedPlayer.getInventory(), i, 0, 0)
for (int i = 0; i < requestedPlayer.getInventory().getContainerSize(); i++) {
gui.setSlot(i, canModify ? new Slot(requestedPlayer.getInventory(), i, 0, 0)
: new UnmodifiableSlot(requestedPlayer.getInventory(), i));
}

Expand All @@ -63,30 +63,30 @@ public static int inv(CommandContext<ServerCommandSource> context) throws Comman
return 1;
}

public static int eChest(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
ServerPlayerEntity player = context.getSource().getPlayer();
ServerPlayerEntity requestedPlayer = getRequestedPlayer(context);
EnderChestInventory requestedEchest = requestedPlayer.getEnderChestInventory();
public static int eChest(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
ServerPlayer player = context.getSource().getPlayer();
ServerPlayer requestedPlayer = getRequestedPlayer(context);
PlayerEnderChestContainer requestedEchest = requestedPlayer.getEnderChestInventory();

boolean canModify = Permissions.check(context.getSource(), permModify, true);

Permissions.check(requestedPlayer.getUuid(), permProtected, false).thenAcceptAsync(isProtected -> {
Permissions.check(requestedPlayer.getUUID(), permProtected, false).thenAcceptAsync(isProtected -> {
if (isProtected) {
context.getSource().sendError(Text.literal(msgProtected));
context.getSource().sendFailure(Component.literal(msgProtected));
} else {
ScreenHandlerType<?> screenHandlerType = switch (requestedEchest.size()) {
case 9 -> ScreenHandlerType.GENERIC_9X1;
case 18 -> ScreenHandlerType.GENERIC_9X2;
case 36 -> ScreenHandlerType.GENERIC_9X4;
case 45 -> ScreenHandlerType.GENERIC_9X5;
case 54 -> ScreenHandlerType.GENERIC_9X6;
default -> ScreenHandlerType.GENERIC_9X3;
MenuType<?> screenHandlerType = switch (requestedEchest.getContainerSize()) {
case 9 -> MenuType.GENERIC_9x1;
case 18 -> MenuType.GENERIC_9x2;
case 36 -> MenuType.GENERIC_9x4;
case 45 -> MenuType.GENERIC_9x5;
case 54 -> MenuType.GENERIC_9x6;
default -> MenuType.GENERIC_9x3;
};
SimpleGui gui = new SavingPlayerDataGui(screenHandlerType, player, requestedPlayer);
gui.setTitle(requestedPlayer.getName());
addBackground(gui);
for (int i = 0; i < requestedEchest.size(); i++) {
gui.setSlotRedirect(i,
for (int i = 0; i < requestedEchest.getContainerSize(); i++) {
gui.setSlot(i,
canModify ? new Slot(requestedEchest, i, 0, 0) : new UnmodifiableSlot(requestedEchest, i));
}

Expand Down Expand Up @@ -162,30 +162,30 @@ public static int eChest(CommandContext<ServerCommandSource> context) throws Com
// return 1;
// }

private static ServerPlayerEntity getRequestedPlayer(CommandContext<ServerCommandSource> context)
private static ServerPlayer getRequestedPlayer(CommandContext<CommandSourceStack> context)
throws CommandSyntaxException {
PlayerConfigEntry playerConfigEntry = GameProfileArgumentType.getProfileArgument(context, "target").iterator().next();
ServerPlayerEntity requestedPlayer = minecraftServer.getPlayerManager().getPlayer(playerConfigEntry.name());
NameAndId playerConfigEntry = GameProfileArgument.getGameProfiles(context, "target").iterator().next();
ServerPlayer requestedPlayer = minecraftServer.getPlayerList().getPlayerByName(playerConfigEntry.name());

// If player is not currently online
if (requestedPlayer == null) {
requestedPlayer = new ServerPlayerEntity(minecraftServer, minecraftServer.getOverworld(), new GameProfile(playerConfigEntry.id(), playerConfigEntry.name()),
SyncedClientOptions.createDefault());
Optional<ReadView> readViewOpt = minecraftServer.getPlayerManager()
.loadPlayerData(playerConfigEntry).map(playerData -> NbtReadView.create(new ErrorReporter.Logging(LogUtils.getLogger()), minecraftServer.getRegistryManager(), playerData));
readViewOpt.ifPresent(requestedPlayer::readData);
requestedPlayer = new ServerPlayer(minecraftServer, minecraftServer.overworld(), new GameProfile(playerConfigEntry.id(), playerConfigEntry.name()),
ClientInformation.createDefault());
Optional<ValueInput> readViewOpt = minecraftServer.getPlayerList()
.loadPlayerData(playerConfigEntry).map(playerData -> TagValueInput.create(new ProblemReporter.ScopedCollector(LogUtils.getLogger()), minecraftServer.registryAccess(), playerData));
readViewOpt.ifPresent(requestedPlayer::load);

// Avoids player's dimension being reset to the overworld
if (readViewOpt.isPresent()) {
ReadView readView = readViewOpt.get();
Optional<String> dimension = readView.getOptionalString("Dimension");
ValueInput readView = readViewOpt.get();
Optional<String> dimension = readView.getString("Dimension");

if (dimension.isPresent()) {
ServerWorld world = minecraftServer.getWorld(
RegistryKey.of(RegistryKeys.WORLD, Identifier.tryParse(dimension.get())));
ServerLevel world = minecraftServer.getLevel(
ResourceKey.create(Registries.DIMENSION, Identifier.tryParse(dimension.get())));

if (world != null) {
((EntityAccessor) requestedPlayer).callSetWorld(world);
((EntityAccessor) requestedPlayer).callSetLevel(world);
}
}
}
Expand All @@ -196,7 +196,7 @@ private static ServerPlayerEntity getRequestedPlayer(CommandContext<ServerComman

private static void addBackground(SimpleGui gui) {
for (int i = 0; i < gui.getSize(); i++) {
gui.setSlot(i, new GuiElementBuilder(Items.BARRIER).setName(Text.literal("")).build());
gui.setSlot(i, new GuiElementBuilder(Items.BARRIER).setName(Component.literal("")).build());
}
}
}
10 changes: 5 additions & 5 deletions src/main/java/us/potatoboy/invview/gui/SavingPlayerDataGui.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package us.potatoboy.invview.gui;

import eu.pb4.sgui.api.gui.SimpleGui;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.MenuType;
import us.potatoboy.invview.InvView;

public class SavingPlayerDataGui extends SimpleGui {
private final ServerPlayerEntity savedPlayer;
private final ServerPlayer savedPlayer;

/**
* Constructs a new simple container gui for the supplied player.
*
* @param type the screen handler that the client should display
* @param player the player to server this gui to
*/
public SavingPlayerDataGui(ScreenHandlerType<?> type, ServerPlayerEntity player, ServerPlayerEntity savedPlayer) {
public SavingPlayerDataGui(MenuType<?> type, ServerPlayer player, ServerPlayer savedPlayer) {
super(type, player, false);
this.savedPlayer = savedPlayer;
}

@Override
public void onClose() {
public void onManualClose() {
InvView.savePlayerData(savedPlayer);
}
}
Loading