diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b01da52..0c2a3f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,30 +8,23 @@ on: [pull_request, push] jobs: build: - strategy: - matrix: - # Use these Java versions - java: [ - 21, # Current Java LTS - ] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v2 - - name: setup jdk ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: gradle/actions/wrapper-validation@v6 + - name: setup jdk + uses: actions/setup-java@v5 with: - java-version: ${{ matrix.java }} + java-version: '25' distribution: 'microsoft' - name: make gradle wrapper executable run: chmod +x ./gradlew - name: build run: ./gradlew build - name: capture build artifacts - if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Artifacts path: build/libs/ \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0dbe321..42a5cd5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version "${loom_version}" + id 'net.fabricmc.fabric-loom' version "${loom_version}" id 'maven-publish' } @@ -35,17 +35,14 @@ loom { 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}" - modImplementation("com.terraformersmc:modmenu:${project.modmenu_version}") + implementation("com.terraformersmc:modmenu:${project.modmenu_version}") - modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_version}") { - exclude(group: "net.fabricmc.fabric-api") - } + implementation("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_version}") } processResources { @@ -57,7 +54,7 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 21 + it.options.release = 25 } java { @@ -66,8 +63,8 @@ java { // If you remove this line, sources will not be generated. withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } jar { @@ -94,4 +91,10 @@ publishing { // The repositories here will be used for publishing your artifact, not for // retrieving dependencies. } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(25) + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 52caf6f..d869230 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,17 +5,16 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.11 -yarn_mappings=1.21.11+build.4 -loader_version=0.18.4 -loom_version=1.14-SNAPSHOT +minecraft_version=26.1.1 +loader_version=0.18.6 +loom_version=1.16-SNAPSHOT # Mod Properties -mod_version=1.1.4+1.21.11 +mod_version=1.1.5+26.1.1 maven_group=borknbeans.lightweightinventorysorting archives_base_name=lightweight-inventory-sorting # Dependencies -fabric_version=0.141.1+1.21.11 -modmenu_version=17.0.0-beta.2 -cloth_version=21.11.153 \ No newline at end of file +fabric_version=0.145.4+26.1.1 +modmenu_version=18.0.0-alpha.8 +cloth_version=26.1.154 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..d997cfc 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 80c4793..c61a118 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-rc-3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/src/client/java/borknbeans/lightweightinventorysorting/LightweightInventorySortingClient.java b/src/client/java/borknbeans/lightweightinventorysorting/LightweightInventorySortingClient.java index f7a05ee..739b4f8 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/LightweightInventorySortingClient.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/LightweightInventorySortingClient.java @@ -1,74 +1,74 @@ package borknbeans.lightweightinventorysorting; import borknbeans.lightweightinventorysorting.config.Config; +import com.mojang.blaze3d.platform.InputConstants; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.option.KeyBinding.Category; -import net.minecraft.client.util.InputUtil; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemGroups; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; - +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.CreativeModeTabs; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import org.lwjgl.glfw.GLFW; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class LightweightInventorySortingClient implements ClientModInitializer { - private final static Map CREATIVE_INDICES = new HashMap<>(); - - public static KeyBinding sortKeyBind; + private final static Map CREATIVE_INDICES = new HashMap<>(); + // Define the category for your mod's keybindings + private static final KeyMapping.Category CATEGORY = KeyMapping.Category.register( + Identifier.fromNamespaceAndPath("lightweight-inventory-sorting", "lightweight-inventory-sorting")); + public static KeyMapping sortKeyBind; - @Override - public void onInitializeClient() { - Config.load(); - registerKeyBindings(); - } - - private void registerKeyBindings() { - sortKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding( - "key.lightweight-inventory-sorting.sort", - InputUtil.Type.KEYSYM, - GLFW.GLFW_KEY_R, - Category.create(Identifier.of("category.lightweight-inventory-sorting.title")) - )); - } + public static int getCreativeIndex(ItemStack itemStack) { + if (CREATIVE_INDICES.isEmpty()) { + reloadIndices(); + } + return CREATIVE_INDICES.getOrDefault(itemStack.getItem(), 0); + } - public static int getCreativeIndex(ItemStack itemStack) { - if (CREATIVE_INDICES.isEmpty()) { - reloadIndices(); - } - return CREATIVE_INDICES.getOrDefault(itemStack.getItem(), 0); - } + public static void reloadIndices() { + LightweightInventorySorting.LOGGER.info("Reloading item order for Lightweight Inventory Sorter"); - /** - * Saves the creative inventory index of all registered items. - * This should run after all items have been registered. - */ - public static void reloadIndices() { - LightweightInventorySorting.LOGGER.info("Reloading item order for Lightweight Inventory Sorter"); + Minecraft client = Minecraft.getInstance(); + CreativeModeTab.ItemDisplayParameters context = new CreativeModeTab.ItemDisplayParameters( + client.player.connection.enabledFeatures(), + false, + client.level.registryAccess() + ); - // For updating the groups (thanks EMI) - MinecraftClient client = MinecraftClient.getInstance(); - ItemGroup.DisplayContext context = new ItemGroup.DisplayContext(client.player.networkHandler.getEnabledFeatures(), false, client.world.getRegistryManager()); + CREATIVE_INDICES.clear(); + List items = new ArrayList<>(); - CREATIVE_INDICES.clear(); + for (CreativeModeTab group : CreativeModeTabs.allTabs()) { + if (group.getType() != CreativeModeTab.Type.SEARCH) { + group.buildContents(context); + items.addAll(group.getDisplayItems()); + } + } - List items = new ArrayList<>(); + for (int i = 0; i < items.size(); i++) { + CREATIVE_INDICES.putIfAbsent(items.get(i).getItem(), i); + } + } - for (ItemGroup group : ItemGroups.getGroups()) { - if (group.getType() != ItemGroup.Type.SEARCH) { - group.updateEntries(context); - items.addAll(group.getSearchTabStacks()); - } - } + @Override + public void onInitializeClient() { + Config.load(); + registerKeyBindings(); + } - for (int i = 0; i < items.size(); i++) { - CREATIVE_INDICES.putIfAbsent(items.get(i).getItem(), i); - } + private void registerKeyBindings() { + sortKeyBind = new KeyMapping( + "key.lightweight-inventory-sorting.sort", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_R, + CATEGORY + ); } -} \ No newline at end of file +} diff --git a/src/client/java/borknbeans/lightweightinventorysorting/config/ButtonSize.java b/src/client/java/borknbeans/lightweightinventorysorting/config/ButtonSize.java index 9e0787c..4ceaf83 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/config/ButtonSize.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/config/ButtonSize.java @@ -1,7 +1,7 @@ package borknbeans.lightweightinventorysorting.config; import borknbeans.lightweightinventorysorting.LightweightInventorySorting; -import net.minecraft.util.Identifier; +import net.minecraft.resources.Identifier; public enum ButtonSize { SMALL, @@ -23,7 +23,7 @@ public Identifier getButtonTexture() { case LARGE -> "sort_button_large"; }; - return Identifier.of(LightweightInventorySorting.MOD_ID, fileName); + return Identifier.fromNamespaceAndPath(LightweightInventorySorting.MOD_ID, fileName); } public Identifier getButtonHoverTexture() { @@ -33,6 +33,6 @@ public Identifier getButtonHoverTexture() { case LARGE -> "sort_button_large_hover"; }; - return Identifier.of(LightweightInventorySorting.MOD_ID, fileName); + return Identifier.fromNamespaceAndPath(LightweightInventorySorting.MOD_ID, fileName); } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/config/Config.java b/src/client/java/borknbeans/lightweightinventorysorting/config/Config.java index 645ad20..625b4e2 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/config/Config.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/config/Config.java @@ -1,16 +1,15 @@ package borknbeans.lightweightinventorysorting.config; +import borknbeans.lightweightinventorysorting.LightweightInventorySorting; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.fabricmc.loader.api.FabricLoader; + import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import borknbeans.lightweightinventorysorting.LightweightInventorySorting; -import net.fabricmc.loader.api.FabricLoader; - public class Config { private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "lightweight-inventory-sorting.json"); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); diff --git a/src/client/java/borknbeans/lightweightinventorysorting/config/ModMenu.java b/src/client/java/borknbeans/lightweightinventorysorting/config/ModMenu.java index 6900283..c6f96a6 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/config/ModMenu.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/config/ModMenu.java @@ -5,8 +5,8 @@ import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; public class ModMenu implements ModMenuApi { @@ -18,44 +18,44 @@ public ConfigScreenFactory getModConfigScreenFactory() { private Screen createConfigScreen(Screen parent) { ConfigBuilder builder = ConfigBuilder.create() .setParentScreen(parent) - .setTitle(Text.translatable("category.lightweight-inventory-sorting.title")); + .setTitle(Component.translatable("category.lightweight-inventory-sorting.title")); ConfigEntryBuilder entryBuilder = builder.entryBuilder(); - ConfigCategory generalSettings = builder.getOrCreateCategory(Text.translatable("category.lightweight-inventory-sorting.general")); + ConfigCategory generalSettings = builder.getOrCreateCategory(Component.translatable("category.lightweight-inventory-sorting.general")); - generalSettings.addEntry(entryBuilder.startTextDescription(Text.translatable("category.lightweight-inventory-sorting.sort-options")) + generalSettings.addEntry(entryBuilder.startTextDescription(Component.translatable("category.lightweight-inventory-sorting.sort-options")) .build()); generalSettings.addEntry(entryBuilder.startEnumSelector( - Text.translatable("category.lightweight-inventory-sorting.sort-type"), + Component.translatable("category.lightweight-inventory-sorting.sort-type"), SortType.class, Config.sortType ).setDefaultValue(SortType.INDEX) .setSaveConsumer(newValue -> Config.sortType = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.sort-type-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.sort-type-tooltip")) .build()); generalSettings.addEntry(entryBuilder.startBooleanToggle( - Text.translatable("category.lightweight-inventory-sorting.reverse-sort"), + Component.translatable("category.lightweight-inventory-sorting.reverse-sort"), Config.reverseSort ).setDefaultValue(false) .setSaveConsumer(newValue -> Config.reverseSort = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.reverse-sort-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.reverse-sort-tooltip")) .build()); generalSettings.addEntry(entryBuilder.startIntField( - Text.translatable("category.lightweight-inventory-sorting.sort-delay"), + Component.translatable("category.lightweight-inventory-sorting.sort-delay"), Config.sortDelay ).setDefaultValue(0) .setSaveConsumer(newValue -> Config.sortDelay = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.sort-delay-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.sort-delay-tooltip")) .build()); - generalSettings.addEntry(entryBuilder.startTextDescription(Text.translatable("category.lightweight-inventory-sorting.button-options")) + generalSettings.addEntry(entryBuilder.startTextDescription(Component.translatable("category.lightweight-inventory-sorting.button-options")) .build()); generalSettings.addEntry(entryBuilder.startEnumSelector( - Text.translatable("category.lightweight-inventory-sorting.button-size"), + Component.translatable("category.lightweight-inventory-sorting.button-size"), ButtonSize.class, Config.buttonSize ).setDefaultValue(ButtonSize.LARGE) @@ -63,35 +63,35 @@ private Screen createConfigScreen(Screen parent) { .build()); generalSettings.addEntry(entryBuilder.startIntField( - Text.translatable("category.lightweight-inventory-sorting.inventory-x"), - Config.xOffsetInventory + Component.translatable("category.lightweight-inventory-sorting.inventory-x"), + Config.xOffsetInventory ).setDefaultValue(0) .setSaveConsumer(newValue -> Config.xOffsetInventory = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.inventory-x-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.inventory-x-tooltip")) .build()); generalSettings.addEntry(entryBuilder.startIntField( - Text.translatable("category.lightweight-inventory-sorting.inventory-y"), + Component.translatable("category.lightweight-inventory-sorting.inventory-y"), Config.yOffsetInventory ).setDefaultValue(0) .setSaveConsumer(newValue -> Config.yOffsetInventory = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.inventory-y-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.inventory-y-tooltip")) .build()); generalSettings.addEntry(entryBuilder.startIntField( - Text.translatable("category.lightweight-inventory-sorting.container-x"), + Component.translatable("category.lightweight-inventory-sorting.container-x"), Config.xOffsetContainer ).setDefaultValue(0) .setSaveConsumer(newValue -> Config.xOffsetContainer = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.container-x-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.container-x-tooltip")) .build()); generalSettings.addEntry(entryBuilder.startIntField( - Text.translatable("category.lightweight-inventory-sorting.container-y"), + Component.translatable("category.lightweight-inventory-sorting.container-y"), Config.yOffsetContainer ).setDefaultValue(0) .setSaveConsumer(newValue -> Config.yOffsetContainer = newValue) - .setTooltip(Text.translatable("category.lightweight-inventory-sorting.container-y-tooltip")) + .setTooltip(Component.translatable("category.lightweight-inventory-sorting.container-y-tooltip")) .build()); builder.setSavingRunnable(Config::save); diff --git a/src/client/java/borknbeans/lightweightinventorysorting/config/SortType.java b/src/client/java/borknbeans/lightweightinventorysorting/config/SortType.java index 235dd4f..e254034 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/config/SortType.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/config/SortType.java @@ -1,15 +1,15 @@ package borknbeans.lightweightinventorysorting.config; import borknbeans.lightweightinventorysorting.LightweightInventorySortingClient; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import java.util.Comparator; public enum SortType { INDEX(Comparator.comparingInt(LightweightInventorySortingClient::getCreativeIndex)), - ALPHANUMERIC(Comparator.comparing(stack -> stack.getName().getString())), - RAW_ID(Comparator.comparingInt(stack -> Item.getRawId(stack.getItem()))); + ALPHANUMERIC(Comparator.comparing(stack -> stack.getItemName().getString())), + RAW_ID(Comparator.comparingInt(stack -> Item.getId(stack.getItem()))); public final Comparator comparator; diff --git a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/GenericContainerScreenMixin.java b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/GenericContainerScreenMixin.java index 44a9e84..27ef974 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/GenericContainerScreenMixin.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/GenericContainerScreenMixin.java @@ -1,72 +1,63 @@ - package borknbeans.lightweightinventorysorting.mixin.client; import borknbeans.lightweightinventorysorting.LightweightInventorySortingClient; import borknbeans.lightweightinventorysorting.config.Config; import borknbeans.lightweightinventorysorting.sorting.SortButton; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.input.KeyInput; -import net.minecraft.client.input.MouseInput; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.GenericContainerScreenHandler; -import net.minecraft.text.Text; +import borknbeans.lightweightinventorysorting.sorting.Sorter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.ContainerScreen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.ChestMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(GenericContainerScreen.class) -public abstract class GenericContainerScreenMixin extends HandledScreen { +@Mixin(ContainerScreen.class) +public abstract class GenericContainerScreenMixin extends AbstractContainerScreen { + @Unique private SortButton sortButton; - public GenericContainerScreenMixin(GenericContainerScreenHandler handler, PlayerInventory inventory, Text title) { - super(handler, inventory, title); + public GenericContainerScreenMixin(ChestMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); } @Override - public void init() { + protected void init() { super.init(); // Initialize button - int x = this.x + this.backgroundWidth - 20 + Config.xOffsetContainer; - int y = this.y + 4 + Config.yOffsetContainer; + int x = this.leftPos + this.imageWidth - 20 + Config.xOffsetContainer; + int y = this.topPos + 4 + Config.yOffsetContainer; int size = Config.buttonSize.getButtonSize(); - sortButton = new SortButton(x, y, size, size, Text.literal("S"), 0, getScreenHandler().slots.size() - 37); + sortButton = new SortButton(x, y, size, size, Component.literal("S"), 0, getMenu().slots.size() - 37); // Add button to the screen - this.addDrawableChild(sortButton); - } - - @Inject(method = "render", at = @At("RETURN")) - private void onRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (sortButton != null) { - sortButton.render(context, mouseX, mouseY, delta); - } + this.addRenderableWidget(sortButton); } @Override - public boolean keyPressed(KeyInput event) { - if (LightweightInventorySortingClient.sortKeyBind.matchesKey(event)) { - // Create a simulated left mouse click (button 0) with no modifiers - MouseInput mouseInput = new MouseInput(0, 0); - Click simulatedClick = new Click(0.0, 0.0, mouseInput); - sortButton.onClick(simulatedClick, false); + public boolean keyPressed(KeyEvent event) { + if (LightweightInventorySortingClient.sortKeyBind.matches(event)) { + if (this.sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } - return super.keyPressed(event); } @Override - public boolean mouseClicked(Click click, boolean doubled) { - if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(click)) { - sortButton.onClick(click, false); // Simulate a click + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(event)) { + if (this.sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } - - return super.mouseClicked(click, doubled); + return super.mouseClicked(event, doubleClick); } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/InventoryScreenMixin.java b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/InventoryScreenMixin.java index deb7b00..54a9701 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/InventoryScreenMixin.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/InventoryScreenMixin.java @@ -1,74 +1,66 @@ package borknbeans.lightweightinventorysorting.mixin.client; +import borknbeans.lightweightinventorysorting.LightweightInventorySortingClient; +import borknbeans.lightweightinventorysorting.config.Config; +import borknbeans.lightweightinventorysorting.sorting.SortButton; +import borknbeans.lightweightinventorysorting.sorting.Sorter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.InventoryScreen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.InventoryMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import borknbeans.lightweightinventorysorting.LightweightInventorySortingClient; -import borknbeans.lightweightinventorysorting.config.Config; -import borknbeans.lightweightinventorysorting.sorting.SortButton; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.gui.screen.ingame.InventoryScreen; -import net.minecraft.client.input.KeyInput; -import net.minecraft.client.input.MouseInput; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.PlayerScreenHandler; -import net.minecraft.text.Text; - @Mixin(InventoryScreen.class) -public abstract class InventoryScreenMixin extends HandledScreen { +public abstract class InventoryScreenMixin extends AbstractContainerScreen { @Unique private SortButton sortButton; - public InventoryScreenMixin(PlayerScreenHandler handler, PlayerInventory inventory, Text title) { - super(handler, inventory, title); + public InventoryScreenMixin(InventoryMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); } @Inject(method = "init", at = @At("RETURN")) private void onInit(CallbackInfo ci) { int size = Config.buttonSize.getButtonSize(); - sortButton = new SortButton(0, 0, size, size, Text.literal("S"), 9, 35); + sortButton = new SortButton(0, 0, size, size, Component.literal("S"), 9, 35); setButtonCoordinates(); - - this.addDrawableChild(sortButton); + this.addRenderableWidget(sortButton); } - @Inject(method = "render", at = @At("RETURN")) - private void onRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (sortButton != null) { - setButtonCoordinates(); - sortButton.render(context, mouseX, mouseY, delta); - } - } - // This override is NOT an ideal solution as it could lead to conflicts with other mods @Override - public boolean keyPressed(KeyInput event) { - if (LightweightInventorySortingClient.sortKeyBind.matchesKey(event)) { - // Create a simulated left mouse click (button 0) with no modifiers - MouseInput mouseInput = new MouseInput(0, 0); - Click simulatedClick = new Click(0.0, 0.0, mouseInput); - sortButton.onClick(simulatedClick, false); + public boolean keyPressed(KeyEvent event) { + if (LightweightInventorySortingClient.sortKeyBind.matches(event)) { + if (sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } return super.keyPressed(event); } @Override - public boolean mouseClicked(Click click, boolean doubled) { - if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(click)) { - sortButton.onClick(click, false); // Simulate a click + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(event)) { + if (sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } - - return super.mouseClicked(click, doubled); + return super.mouseClicked(event, doubleClick); } - + private void setButtonCoordinates() { - sortButton.setX(this.x + this.backgroundWidth - 20 + Config.xOffsetInventory); + sortButton.setX(this.leftPos + this.imageWidth - 20 + Config.xOffsetInventory); sortButton.setY(this.height / 2 - 15 + Config.yOffsetInventory); } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/ShulkerBoxScreenMixin.java b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/ShulkerBoxScreenMixin.java index e91ef08..0c308f2 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/ShulkerBoxScreenMixin.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/mixin/client/ShulkerBoxScreenMixin.java @@ -3,69 +3,59 @@ import borknbeans.lightweightinventorysorting.LightweightInventorySortingClient; import borknbeans.lightweightinventorysorting.config.Config; import borknbeans.lightweightinventorysorting.sorting.SortButton; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.gui.screen.ingame.ShulkerBoxScreen; -import net.minecraft.client.input.KeyInput; -import net.minecraft.client.input.MouseInput; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.ShulkerBoxScreenHandler; -import net.minecraft.text.Text; +import borknbeans.lightweightinventorysorting.sorting.Sorter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.ShulkerBoxScreen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.ShulkerBoxMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ShulkerBoxScreen.class) -public abstract class ShulkerBoxScreenMixin extends HandledScreen { +public abstract class ShulkerBoxScreenMixin extends AbstractContainerScreen { + @Unique private SortButton sortButton; - public ShulkerBoxScreenMixin(ShulkerBoxScreenHandler handler, PlayerInventory inventory, Text title) { - super(handler, inventory, title); + public ShulkerBoxScreenMixin(ShulkerBoxMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); } @Override - public void init() { + protected void init() { super.init(); - // Initialize button - int x = this.x + this.backgroundWidth - 20 + Config.xOffsetContainer; - int y = this.y + 4 + Config.yOffsetContainer; + int x = this.leftPos + this.imageWidth - 20 + Config.xOffsetContainer; + int y = this.topPos + 4 + Config.yOffsetContainer; int size = Config.buttonSize.getButtonSize(); - sortButton = new SortButton(x, y, size, size, Text.literal("S"), 0, getScreenHandler().slots.size() - 37); - - // Add button to the screen - this.addDrawableChild(sortButton); + sortButton = new SortButton(x, y, size, size, Component.literal("S"), 0, getMenu().slots.size() - 37); + this.addRenderableWidget(sortButton); } - @Inject(method = "render", at = @At("RETURN")) - private void onRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (sortButton != null) { - sortButton.render(context, mouseX, mouseY, delta); - } - } @Override - public boolean keyPressed(KeyInput event) { - if (LightweightInventorySortingClient.sortKeyBind.matchesKey(event)) { - // Create a simulated left mouse click (button 0) with no modifiers - MouseInput mouseInput = new MouseInput(0, 0); - Click simulatedClick = new Click(0.0, 0.0, mouseInput); - sortButton.onClick(simulatedClick, false); + public boolean keyPressed(KeyEvent event) { + if (LightweightInventorySortingClient.sortKeyBind.matches(event)) { + if (sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } - return super.keyPressed(event); } @Override - public boolean mouseClicked(Click click, boolean doubled) { - if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(click)) { - sortButton.onClick(click, false); // Simulate a click + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (LightweightInventorySortingClient.sortKeyBind.matchesMouse(event)) { + if (sortButton != null) { + Sorter.sortContainerClientside(Minecraft.getInstance(), sortButton.getSortStartIndex(), sortButton.getSortEndIndex()); + } + return true; } - - return super.mouseClicked(click, doubled); + return super.mouseClicked(event, doubleClick); } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/sorting/ClickOperation.java b/src/client/java/borknbeans/lightweightinventorysorting/sorting/ClickOperation.java index daee57f..220ebff 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/sorting/ClickOperation.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/sorting/ClickOperation.java @@ -1,14 +1,13 @@ package borknbeans.lightweightinventorysorting.sorting; -import java.util.List; +import net.minecraft.client.Minecraft; +import net.minecraft.world.inventory.ContainerInput; +import net.minecraft.world.item.ItemStack; -import borknbeans.lightweightinventorysorting.config.Config; -import net.minecraft.client.MinecraftClient; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.slot.SlotActionType; +import java.util.List; public class ClickOperation { - private final MinecraftClient client; + private final Minecraft client; private final int syncId; private final int targetSlot; private final ItemStack expectedStartingTargetStack; @@ -18,7 +17,7 @@ public class ClickOperation { private final List delays = List.of(0, 5, 15); // in milliseconds - public ClickOperation(MinecraftClient client, int syncId, int targetSlot, ItemStack expectedStartingTargetStack, ItemStack expectedEndingTargetStack, ItemStack expectedStartingMouseStack, ItemStack expectedEndingMouseStack) { + public ClickOperation(Minecraft client, int syncId, int targetSlot, ItemStack expectedStartingTargetStack, ItemStack expectedEndingTargetStack, ItemStack expectedStartingMouseStack, ItemStack expectedEndingMouseStack) { this.client = client; this.syncId = syncId; this.targetSlot = targetSlot; @@ -34,12 +33,12 @@ public void execute() throws Exception { } ItemStack startingMouseStack = Sorter.getMouseStack(client); - if (!ItemStack.areItemsAndComponentsEqual(startingMouseStack, expectedStartingMouseStack)) { + if (!ItemStack.isSameItemSameComponents(startingMouseStack, expectedStartingMouseStack)) { throw new Exception("[Target: " + targetSlot + "] Starting mouse stack is not what we expected: (ACTUAL)" + getItemStackString(startingMouseStack) + " != (EXPECTED)" + getItemStackString(expectedStartingMouseStack)); } ItemStack startingTargetStack = Sorter.getInventoryStack(client, targetSlot); - if (!ItemStack.areItemsAndComponentsEqual(startingTargetStack, expectedStartingTargetStack)) { + if (!ItemStack.isSameItemSameComponents(startingTargetStack, expectedStartingTargetStack)) { throw new Exception("[Target: " + targetSlot + "] Starting target stack is not what we expected: (ACTUAL)" + getItemStackString(startingTargetStack) + " != (EXPECTED)" + getItemStackString(expectedStartingTargetStack)); } @@ -50,8 +49,10 @@ public void execute() throws Exception { for (int i = 0; i < delays.size(); i++) { try { Thread.sleep(delays.get(i)); - } catch (InterruptedException e) {} - + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + try { postClickVerification(); return; @@ -69,23 +70,22 @@ private void click() { if (client.player == null) { return; } - - client.interactionManager.clickSlot(syncId, targetSlot, 0, SlotActionType.PICKUP, client.player); + client.gameMode.handleContainerInput(syncId, targetSlot, 0, ContainerInput.PICKUP, client.player); } - private void postClickVerification() throws Exception{ - var endingMouseStack = Sorter.getMouseStack(client); - if (!ItemStack.areItemsAndComponentsEqual(endingMouseStack, expectedEndingMouseStack)) { + private void postClickVerification() throws Exception { + ItemStack endingMouseStack = Sorter.getMouseStack(client); + if (!ItemStack.isSameItemSameComponents(endingMouseStack, expectedEndingMouseStack)) { throw new Exception("[Target: " + targetSlot + "] Ending mouse stack is not what we expected: (ACTUAL)" + getItemStackString(endingMouseStack) + " != (EXPECTED)" + getItemStackString(expectedEndingMouseStack)); } - var targetStack = Sorter.getInventoryStack(client, targetSlot); - if (!ItemStack.areItemsAndComponentsEqual(targetStack, expectedEndingTargetStack)) { + ItemStack targetStack = Sorter.getInventoryStack(client, targetSlot); + if (!ItemStack.isSameItemSameComponents(targetStack, expectedEndingTargetStack)) { throw new Exception("[Target: " + targetSlot + "] Ending target stack is not what we expected: (ACTUAL)" + getItemStackString(targetStack) + " != (EXPECTED)" + getItemStackString(expectedEndingTargetStack)); } } private String getItemStackString(ItemStack stack) { - return String.format("%dx %s", stack.getCount(), stack.getItem().getName().getString()); + return String.format("%dx %s", stack.getCount(), stack.getItem().getName(stack).getString()); } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortButton.java b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortButton.java index 21aee55..4aa48c0 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortButton.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortButton.java @@ -1,54 +1,49 @@ package borknbeans.lightweightinventorysorting.sorting; -import com.mojang.blaze3d.pipeline.RenderPipeline; - import borknbeans.lightweightinventorysorting.LightweightInventorySorting; import borknbeans.lightweightinventorysorting.config.Config; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.RenderPipelines; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - -public class SortButton extends ClickableWidget { +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarratedElementType; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; - private Identifier buttonTexture; - private Identifier buttonHoverTexture; +public class SortButton extends AbstractWidget { - private int sortStartIndex, sortEndIndex; + private final Identifier buttonTexture; + private final Identifier buttonHoverTexture; + private final int sortStartIndex; + private final int sortEndIndex; - public SortButton(int x, int y, int width, int height, Text message, int startIndex, int endIndex) { + public SortButton(int x, int y, int width, int height, Component message, int startIndex, int endIndex) { super(x, y, width, height, message); - this.sortStartIndex = startIndex; this.sortEndIndex = endIndex; + this.buttonTexture = Config.buttonSize.getButtonTexture(); + this.buttonHoverTexture = Config.buttonSize.getButtonHoverTexture(); + } - buttonTexture = Config.buttonSize.getButtonTexture(); - buttonHoverTexture = Config.buttonSize.getButtonHoverTexture(); + public int getSortStartIndex() { + return sortStartIndex; } - @Override - protected void appendClickableNarrations(NarrationMessageBuilder builder) { - // Narration message if needed + public int getSortEndIndex() { + return sortEndIndex; } @Override - protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { - if (this.isHovered()) { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, buttonHoverTexture, this.getX(), this.getY(), this.getWidth(), this.getHeight()); - } else { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, buttonTexture, this.getX(), this.getY(), this.getWidth(), this.getHeight()); - } + protected void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { + Identifier texture = this.isHovered() ? buttonHoverTexture : buttonTexture; + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, texture, this.getX(), this.getY(), this.getWidth(), this.getHeight()); } @Override - public void onClick(Click click, boolean doubled) { - MinecraftClient client = MinecraftClient.getInstance(); - + public void onClick(MouseButtonEvent event, boolean doubleClick) { + Minecraft client = Minecraft.getInstance(); if (client.player != null) { Sorter.sortContainerClientside(client, sortStartIndex, sortEndIndex); // TODO: handle server-side sorting if enabled @@ -56,5 +51,16 @@ public void onClick(Click click, boolean doubled) { LightweightInventorySorting.LOGGER.error("Player is not available."); } } - + + @Override + protected void updateWidgetNarration(NarrationElementOutput output) { + output.add(NarratedElementType.TITLE, this.createNarrationMessage()); + if (this.active) { + if (this.isFocused()) { + output.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.focused")); + } else { + output.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered")); + } + } + } } diff --git a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortComparator.java b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortComparator.java index 24874fb..6214ced 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortComparator.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortComparator.java @@ -1,12 +1,13 @@ package borknbeans.lightweightinventorysorting.sorting; -import java.util.Comparator; import borknbeans.lightweightinventorysorting.config.Config; -import net.minecraft.item.ItemStack; +import net.minecraft.world.item.ItemStack; + +import java.util.Comparator; public class SortComparator implements Comparator { @Override public int compare(ItemStack o1, ItemStack o2) { return Config.sortType.compare(o1, o2); } -} \ No newline at end of file +} diff --git a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortSnapshotClientside.java b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortSnapshotClientside.java index dbf415e..cd23acc 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortSnapshotClientside.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/sorting/SortSnapshotClientside.java @@ -1,8 +1,8 @@ package borknbeans.lightweightinventorysorting.sorting; import com.google.gson.*; -import net.minecraft.item.ItemStack; -import net.minecraft.registry.Registries; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ItemStack; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -19,17 +19,17 @@ public SortSnapshotClientside(List inventory) { } public String encode() { - var gson = new GsonBuilder() - .registerTypeAdapter(ItemStack.class, new ItemStackSerializer()) - .create(); - var json = gson.toJson(this); - + Gson gson = new GsonBuilder() + .registerTypeAdapter(ItemStack.class, new ItemStackSerializer()) + .create(); + String json = gson.toJson(this); + try { - var baos = new ByteArrayOutputStream(); - var gzipOut = new GZIPOutputStream(baos); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gzipOut = new GZIPOutputStream(baos); gzipOut.write(json.getBytes()); gzipOut.close(); - + return Base64.getEncoder().encodeToString(baos.toByteArray()); } catch (IOException e) { throw new RuntimeException("Failed to compress inventory data", e); @@ -39,17 +39,14 @@ public String encode() { private static class ItemStackSerializer implements JsonSerializer { @Override public JsonElement serialize(ItemStack src, Type typeOfSrc, JsonSerializationContext context) { - var json = new JsonObject(); - + JsonObject json = new JsonObject(); if (src.isEmpty()) { json.addProperty("empty", true); return json; } - - json.addProperty("id", Registries.ITEM.getId(src.getItem()).toString()); + json.addProperty("id", BuiltInRegistries.ITEM.getKey(src.getItem()).toString()); json.addProperty("count", src.getCount()); - return json; } } -} \ No newline at end of file +} diff --git a/src/client/java/borknbeans/lightweightinventorysorting/sorting/Sorter.java b/src/client/java/borknbeans/lightweightinventorysorting/sorting/Sorter.java index 24790f8..4a66788 100644 --- a/src/client/java/borknbeans/lightweightinventorysorting/sorting/Sorter.java +++ b/src/client/java/borknbeans/lightweightinventorysorting/sorting/Sorter.java @@ -1,21 +1,24 @@ package borknbeans.lightweightinventorysorting.sorting; -import java.util.ArrayList; -import java.util.List; - import borknbeans.lightweightinventorysorting.LightweightInventorySorting; import borknbeans.lightweightinventorysorting.config.Config; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.item.BundleItem; -import net.minecraft.item.ItemStack; +import net.minecraft.client.Minecraft; +import net.minecraft.core.NonNullList; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.BundleItem; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; public class Sorter { - private static boolean isSorting = false; + private static volatile boolean isSorting = false; - public static void sortContainerClientside(MinecraftClient client, int sortStartIndex, int sortEndIndex) { + public static void sortContainerClientside(Minecraft client, int sortStartIndex, int sortEndIndex) { if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { return; } @@ -25,10 +28,11 @@ public static void sortContainerClientside(MinecraftClient client, int sortStart LightweightInventorySorting.LOGGER.info("Starting clientside sort"); - var syncId = client.player.currentScreenHandler.syncId; + AbstractContainerMenu container = client.player.containerMenu; + int syncId = container.containerId; - var snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); - var snapshotEncoder = new SortSnapshotClientside(snapshot); + List snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); + SortSnapshotClientside snapshotEncoder = new SortSnapshotClientside(snapshot); LightweightInventorySorting.LOGGER.info("Encoded snapshot: " + snapshotEncoder.encode()); // Run the sort in a new thread @@ -46,55 +50,55 @@ public static void sortContainerClientside(MinecraftClient client, int sortStart }).start(); } - private static void clearMouseStack(MinecraftClient client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { - var snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); + private static void clearMouseStack(Minecraft client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { + List snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); // Clear any existing item that is on the mouse - var mouseStack = getMouseStack(client).copy(); + ItemStack mouseStack = getMouseStack(client).copy(); if (!mouseStack.isEmpty()) { - var emptyIndex = getEmptySlotIndex(snapshot); + int emptyIndex = getEmptySlotIndex(snapshot); if (emptyIndex == -1) { throw new Exception("[Sort] No empty slot found to clear mouse stack"); } - var emptySlotOperation = new ClickOperation(client, syncId, sortStartIndex + emptyIndex, ItemStack.EMPTY, mouseStack, mouseStack, ItemStack.EMPTY); + ClickOperation emptySlotOperation = new ClickOperation(client, syncId, sortStartIndex + emptyIndex, ItemStack.EMPTY, mouseStack, mouseStack, ItemStack.EMPTY); emptySlotOperation.execute(); } } - private static void combineLikeStacks(MinecraftClient client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { - var snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); - var mouseStack = getMouseStack(client); + private static void combineLikeStacks(Minecraft client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { + List snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); + ItemStack mouseStack = getMouseStack(client); if (!mouseStack.isEmpty()) { throw new Exception("[CombineLikeStacks] Mouse stack is not empty"); } for (int i = 0; i < snapshot.size(); i++) { - var stackOriginal = snapshot.get(i).copy(); + ItemStack stackOriginal = snapshot.get(i).copy(); mouseStack = getMouseStack(client); - if (stackOriginal.isEmpty() || stackOriginal.getCount() == stackOriginal.getMaxCount()) { + if (stackOriginal.isEmpty() || stackOriginal.getCount() == stackOriginal.getMaxStackSize()) { continue; } for (int j = i + 1; j < snapshot.size(); j++) { - var otherStack = snapshot.get(j).copy(); - if (otherStack.isEmpty() || otherStack.getCount() == otherStack.getMaxCount()) { + ItemStack otherStack = snapshot.get(j).copy(); + if (otherStack.isEmpty() || otherStack.getCount() == otherStack.getMaxStackSize()) { continue; } - var stack = mouseStack.isEmpty() ? stackOriginal : mouseStack; + ItemStack stack = mouseStack.isEmpty() ? stackOriginal : mouseStack; - if (ItemStack.areItemsAndComponentsEqual(stack, otherStack)) { - var maxStackSize = stack.getMaxCount(); - var combinedSize = stack.getCount() + otherStack.getCount(); + if (ItemStack.isSameItemSameComponents(stack, otherStack)) { + int maxStackSize = stack.getMaxStackSize(); + int combinedSize = stack.getCount() + otherStack.getCount(); - var pickupFirstStack = new ClickOperation(client, syncId, i + sortStartIndex, stack, ItemStack.EMPTY, mouseStack, stack); + ClickOperation pickupFirstStack = new ClickOperation(client, syncId, i + sortStartIndex, stack, ItemStack.EMPTY, mouseStack, stack); - var expectedEndingMouseStack = combinedSize > maxStackSize ? stack.copyWithCount(combinedSize - maxStackSize) : ItemStack.EMPTY; - var combineStacks = new ClickOperation(client, syncId, j + sortStartIndex, otherStack, stack.copyWithCount(Math.min(combinedSize, maxStackSize)), stack, expectedEndingMouseStack); + ItemStack expectedEndingMouseStack = combinedSize > maxStackSize ? stack.copyWithCount(combinedSize - maxStackSize) : ItemStack.EMPTY; + ClickOperation combineStacks = new ClickOperation(client, syncId, j + sortStartIndex, otherStack, stack.copyWithCount(Math.min(combinedSize, maxStackSize)), stack, expectedEndingMouseStack); try { - if (mouseStack.isEmpty()) { // Dont pickup first stack if we have a stack in our hand from the previous iteration + if (mouseStack.isEmpty()) { // Don't pick up first stack if we have a stack in our hand from the previous iteration pickupFirstStack.execute(); } Thread.sleep(Config.sortDelay); @@ -112,7 +116,7 @@ private static void combineLikeStacks(MinecraftClient client, int syncId, int so } if (!mouseStack.isEmpty()) { - var putBackStack = new ClickOperation(client, syncId, i + sortStartIndex, ItemStack.EMPTY, mouseStack, mouseStack, ItemStack.EMPTY); + ClickOperation putBackStack = new ClickOperation(client, syncId, i + sortStartIndex, ItemStack.EMPTY, mouseStack, mouseStack, ItemStack.EMPTY); try { putBackStack.execute(); @@ -125,12 +129,12 @@ private static void combineLikeStacks(MinecraftClient client, int syncId, int so } } - private static void sort(MinecraftClient client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { - var snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); + private static void sort(Minecraft client, int syncId, int sortStartIndex, int sortEndIndex) throws Exception { + List snapshot = getInventorySnapshot(client, sortStartIndex, sortEndIndex); - var sortedStacks = new ArrayList(); + ArrayList sortedStacks = new ArrayList(); for (int i = 0; i < snapshot.size(); i++) { - var stack = snapshot.get(i).copy(); + ItemStack stack = snapshot.get(i).copy(); if (stack.isEmpty()) { continue; } @@ -140,18 +144,18 @@ private static void sort(MinecraftClient client, int syncId, int sortStartIndex, sortedStacks.sort(new SortComparator()); - var mouseStack = getMouseStack(client); + ItemStack mouseStack = getMouseStack(client); if (!mouseStack.isEmpty()) { throw new Exception("[Sort] Mouse stack is not empty"); } for (int i = 0; i < sortedStacks.size(); i++) { - var sortedStack = sortedStacks.get(i); + ItemStack sortedStack = sortedStacks.get(i); - var stackCurrIndex = -1; + int stackCurrIndex = -1; for (int j = i; j < snapshot.size(); j++) { - if (ItemStack.areItemsAndComponentsEqual(sortedStack, snapshot.get(j)) && sortedStack.getCount() == snapshot.get(j).getCount()) { + if (ItemStack.isSameItemSameComponents(sortedStack, snapshot.get(j)) && sortedStack.getCount() == snapshot.get(j).getCount()) { stackCurrIndex = j + sortStartIndex; break; } @@ -165,14 +169,14 @@ private static void sort(MinecraftClient client, int syncId, int sortStartIndex, continue; } - var pickupOperation = new ClickOperation(client, syncId, stackCurrIndex, sortedStack, ItemStack.EMPTY, ItemStack.EMPTY, sortedStack); + ClickOperation pickupOperation = new ClickOperation(client, syncId, stackCurrIndex, sortedStack, ItemStack.EMPTY, ItemStack.EMPTY, sortedStack); - var existingStack = snapshot.get(i).copy(); + ItemStack existingStack = snapshot.get(i).copy(); // If the item that is in our desired slot is a bundle, we need to handle it differently if (existingStack.getItem() instanceof BundleItem) { - var pickupBundleOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, ItemStack.EMPTY, ItemStack.EMPTY, existingStack); - var placeBundleElsewhereOperation = new ClickOperation(client, syncId, getEmptySlotIndex(snapshot) + sortStartIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); + ClickOperation pickupBundleOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, ItemStack.EMPTY, ItemStack.EMPTY, existingStack); + ClickOperation placeBundleElsewhereOperation = new ClickOperation(client, syncId, getEmptySlotIndex(snapshot) + sortStartIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); pickupBundleOperation.execute(); placeBundleElsewhereOperation.execute(); @@ -180,21 +184,21 @@ private static void sort(MinecraftClient client, int syncId, int sortStartIndex, existingStack = ItemStack.EMPTY; } - var placeOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, sortedStack, sortedStack, existingStack); + ClickOperation placeOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, sortedStack, sortedStack, existingStack); + + ClickOperation emptyHandOperation = new ClickOperation(client, syncId, stackCurrIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); - var emptyHandOperation = new ClickOperation(client, syncId, stackCurrIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); - // If the item we are sorting is a bundle, we need to handle it differently if (sortedStack.getItem() instanceof BundleItem) { if (!existingStack.isEmpty()) { - var pickupTargetSlotOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, ItemStack.EMPTY, ItemStack.EMPTY, existingStack); - var emptySlotIndex = getEmptySlotIndex(snapshot); + ClickOperation pickupTargetSlotOperation = new ClickOperation(client, syncId, i + sortStartIndex, existingStack, ItemStack.EMPTY, ItemStack.EMPTY, existingStack); + int emptySlotIndex = getEmptySlotIndex(snapshot); if (emptySlotIndex == -1) { throw new Exception("[Sort] No empty slot found"); } - var placeInEmptySlotOperation = new ClickOperation(client, syncId, sortStartIndex + emptySlotIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); + ClickOperation placeInEmptySlotOperation = new ClickOperation(client, syncId, sortStartIndex + emptySlotIndex, ItemStack.EMPTY, existingStack, existingStack, ItemStack.EMPTY); pickupTargetSlotOperation.execute(); placeInEmptySlotOperation.execute(); @@ -218,10 +222,10 @@ private static void sort(MinecraftClient client, int syncId, int sortStartIndex, } for (int i = 0; i < sortedStacks.size(); i++) { - var expectedStack = sortedStacks.get(i).copy(); - var actualStack = snapshot.get(i).copy(); + ItemStack expectedStack = sortedStacks.get(i).copy(); + ItemStack actualStack = snapshot.get(i).copy(); - if (!ItemStack.areItemsAndComponentsEqual(expectedStack, actualStack)) { + if (!ItemStack.isSameItemSameComponents(expectedStack, actualStack)) { throw new Exception("[Sort] Stack not in correct position"); } } @@ -236,8 +240,8 @@ private static void sort(MinecraftClient client, int syncId, int sortStartIndex, * 36-44: hotbar * 45: offhand */ - private static List getInventorySnapshot(MinecraftClient client, int sortStartIndex, int sortEndIndex) { - var slots = client.player.currentScreenHandler.slots; + private static List getInventorySnapshot(Minecraft client, int sortStartIndex, int sortEndIndex) { + NonNullList slots = client.player.containerMenu.slots; List snapshot = new ArrayList<>(); for (int i = 0; i < slots.size(); i++) { @@ -245,7 +249,7 @@ private static List getInventorySnapshot(MinecraftClient client, int continue; } - snapshot.add(slots.get(i).getStack()); + snapshot.add(slots.get(i).getItem()); } return snapshot; @@ -260,19 +264,19 @@ private static int getEmptySlotIndex(List snapshot) { return -1; } - public static ItemStack getInventoryStack(MinecraftClient client, int index) { + public static ItemStack getInventoryStack(Minecraft client, int index) { if (client.player == null) { return ItemStack.EMPTY; } - return client.player.currentScreenHandler.getSlot(index).getStack(); + return client.player.containerMenu.getSlot(index).getItem(); } - public static ItemStack getMouseStack(MinecraftClient client) { + public static ItemStack getMouseStack(Minecraft client) { if (client.player == null) { return ItemStack.EMPTY; } - return client.player.currentScreenHandler.getCursorStack(); + return client.player.containerMenu.getCarried(); } } diff --git a/src/main/java/borknbeans/lightweightinventorysorting/LightweightInventorySorting.java b/src/main/java/borknbeans/lightweightinventorysorting/LightweightInventorySorting.java index 3ad5ad3..98678b5 100644 --- a/src/main/java/borknbeans/lightweightinventorysorting/LightweightInventorySorting.java +++ b/src/main/java/borknbeans/lightweightinventorysorting/LightweightInventorySorting.java @@ -1,46 +1,15 @@ package borknbeans.lightweightinventorysorting; import net.fabricmc.api.ModInitializer; -// import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; -// import net.minecraft.text.Text; - -// import static net.minecraft.server.command.CommandManager.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LightweightInventorySorting implements ModInitializer { - public static final String MOD_ID = "lightweight-inventory-sorting"; - - // This logger is used to write text to the console and the log file. - // It is considered best practice to use your mod id as the logger's name. - // That way, it's clear which mod wrote info, warnings, and errors. - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - public static final String ENCODED_SNAPSHOT = "H4sIAAAAAAAA/8XTwQ6CMAyA4XfpmYMIHtyrGEPGNuLiaEkdEkN4d49EbQRE4/3Ltv7bevB4dRiJb6AOPXgLCmqPzrCuomooekJIwFCLEVQ6JC+m9GxORRM0ni+j3P6bZj+QuSA/T5RuBBp90zhbaGbqJuZeQMsWbXDvD2k1WhcmZ5nLPMdR7EWha0I7op3UY0XedcnmbPztZE9BcimIIcYqUOd44Wric3u8JuknyMmybDgOd5oBulY9BAAA"; - - @Override - public void onInitialize() { - // CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("lis-load") - // .executes(context -> { - // var snapshot = new SortSnapshotServerside().decode(ENCODED_SNAPSHOT); - - // var source = context.getSource(); - // var player = source.getPlayer(); - - // if (player == null) { - // source.sendFeedback(() -> Text.literal("Player is null"), false); - // return 1; - // } - - // var i = 9; - // for (var item : snapshot.inventory) { - // player.getInventory().setStack(i, item); - // i++; - // } - - // return 1; - // }))); - - LOGGER.info("Lightweight Inventory Sorting initialized on the server!"); - } -} \ No newline at end of file + public static final String MOD_ID = "lightweight-inventory-sorting"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + @Override + public void onInitialize() { + LOGGER.info("Lightweight Inventory Sorting initialized on the server!"); + } +} diff --git a/src/main/java/borknbeans/lightweightinventorysorting/SortSnapshotServerside.java b/src/main/java/borknbeans/lightweightinventorysorting/SortSnapshotServerside.java index 5d9c17e..458d57e 100644 --- a/src/main/java/borknbeans/lightweightinventorysorting/SortSnapshotServerside.java +++ b/src/main/java/borknbeans/lightweightinventorysorting/SortSnapshotServerside.java @@ -1,9 +1,9 @@ package borknbeans.lightweightinventorysorting; import com.google.gson.*; -import net.minecraft.item.ItemStack; -import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; +import net.minecraft.world.item.ItemStack; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -18,23 +18,23 @@ public class SortSnapshotServerside { public SortSnapshotServerside decode(String compressedData) { try { - var decoded = Base64.getDecoder().decode(compressedData); - var bais = new ByteArrayInputStream(decoded); - var gzipIn = new GZIPInputStream(bais); - - var buffer = new byte[1024]; - var baos = new ByteArrayOutputStream(); + byte[] decoded = Base64.getDecoder().decode(compressedData); + ByteArrayInputStream bais = new ByteArrayInputStream(decoded); + GZIPInputStream gzipIn = new GZIPInputStream(bais); + + byte[] buffer = new byte[1024]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len; while ((len = gzipIn.read(buffer)) > 0) { baos.write(buffer, 0, len); } gzipIn.close(); - - var json = baos.toString(); - - var gson = new GsonBuilder() - .registerTypeAdapter(ItemStack.class, new ItemStackDeserializer()) - .create(); + + String json = baos.toString(); + Gson gson = new GsonBuilder() + .registerTypeAdapter(ItemStack.class, new ItemStackDeserializer()) + .create(); + return gson.fromJson(json, SortSnapshotServerside.class); } catch (IOException e) { throw new RuntimeException("Failed to decompress inventory data", e); @@ -44,21 +44,19 @@ public SortSnapshotServerside decode(String compressedData) { private static class ItemStackDeserializer implements JsonDeserializer { @Override public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - var obj = json.getAsJsonObject(); - + JsonObject obj = json.getAsJsonObject(); + if (obj.has("empty") && obj.get("empty").getAsBoolean()) { return ItemStack.EMPTY; } - var id = obj.get("id").getAsString(); - var count = obj.get("count").getAsInt(); - - // TODO: Handle item components - idk how to do this - var item = Registries.ITEM.get(Identifier.of(id)); - var stack = new ItemStack(item); - stack.setCount(count); + DataResult result = ItemStack.CODEC.parse(JsonOps.INSTANCE, obj); + + if (result.error().isPresent()) { + throw new JsonParseException("Failed to deserialize ItemStack: " + result.error().get().message()); + } - return stack; + return result.result().orElse(ItemStack.EMPTY); } } -} \ No newline at end of file +} diff --git a/src/main/java/borknbeans/lightweightinventorysorting/mixin/ExampleMixin.java b/src/main/java/borknbeans/lightweightinventorysorting/mixin/ExampleMixin.java deleted file mode 100644 index e8904f6..0000000 --- a/src/main/java/borknbeans/lightweightinventorysorting/mixin/ExampleMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package borknbeans.lightweightinventorysorting.mixin; - -import net.minecraft.server.MinecraftServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftServer.class) -public class ExampleMixin { - @Inject(at = @At("HEAD"), method = "loadWorld") - private void init(CallbackInfo info) { - // This code is injected into the start of MinecraftServer.loadWorld()V - } -} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index eeb60b3..0c12e07 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -39,7 +39,7 @@ ], "depends": { "fabricloader": ">=0.16.14", - "minecraft": "~1.21.8", + "minecraft": "~26.1.1", "java": ">=21", "fabric-api": "*" }, diff --git a/src/main/resources/lightweight-inventory-sorting.mixins.json b/src/main/resources/lightweight-inventory-sorting.mixins.json index 0ac03bb..57e282b 100644 --- a/src/main/resources/lightweight-inventory-sorting.mixins.json +++ b/src/main/resources/lightweight-inventory-sorting.mixins.json @@ -1,10 +1,8 @@ { "required": true, "package": "borknbeans.lightweightinventorysorting.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "ExampleMixin" - ], + "compatibilityLevel": "JAVA_25", + "mixins": [], "injectors": { "defaultRequire": 1 }