aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2024-04-21 11:30:03 -0400
committerGravatar Chris Xiong <chirs241097@gmail.com> 2024-04-21 11:30:03 -0400
commit083ddabb85d0acab1127f2c70765ef76ad0631fb (patch)
tree584d82d42de265cc35290dadc43c08a113912749
parent31aa0a803069513d32e242a65c4d7ad1daf99355 (diff)
downloadmeteor-trashy-addon-083ddabb85d0acab1127f2c70765ef76ad0631fb.tar.xz
1.20.4 + AutoTrade.
-rw-r--r--gradle.properties8
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin61574 -> 62076 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xgradlew11
-rw-r--r--gradlew.bat184
-rw-r--r--src/main/java/org/chrisoft/trashyaddon/Addon.java4
-rw-r--r--src/main/java/org/chrisoft/trashyaddon/mixin/MerchantScreenAccessor.java14
-rw-r--r--src/main/java/org/chrisoft/trashyaddon/modules/AutoTrade.java330
-rw-r--r--src/main/resources/addon.mixins.json4
-rw-r--r--src/main/resources/assets/template/icon.pngbin2137 -> 2362 bytes
10 files changed, 453 insertions, 104 deletions
diff --git a/gradle.properties b/gradle.properties
index ef58c47..2d09ec9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,9 @@
org.gradle.jvmargs=-Xmx2G
# Fabric Properties (https://fabricmc.net/develop)
-minecraft_version=1.19.4
-yarn_mappings=1.19.4+build.2
-loader_version=0.14.19
+minecraft_version=1.20.4
+yarn_mappings=1.20.4+build.3
+loader_version=0.15.7
# Mod Properties
mod_version=0.0.1
@@ -13,4 +13,4 @@ archives_base_name=meteor-trashy-addon
# Dependencies
# Meteor (https://maven.meteordev.org)
-meteor_version=0.5.3-SNAPSHOT
+meteor_version=0.5.6-SNAPSHOT
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 943f0cb..c1962a7 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37aef8d..20db9ad 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 65dcd68..aeb74cb 100755
--- a/gradlew
+++ b/gradlew
@@ -85,9 +85,6 @@ done
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -144,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -152,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then
done
fi
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
diff --git a/gradlew.bat b/gradlew.bat
index 93e3f59..6689b85 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,92 +1,92 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/org/chrisoft/trashyaddon/Addon.java b/src/main/java/org/chrisoft/trashyaddon/Addon.java
index a956b6c..eb197ff 100644
--- a/src/main/java/org/chrisoft/trashyaddon/Addon.java
+++ b/src/main/java/org/chrisoft/trashyaddon/Addon.java
@@ -1,9 +1,11 @@
package org.chrisoft.trashyaddon;
import org.chrisoft.trashyaddon.commands.*;
+import org.chrisoft.trashyaddon.modules.*;
import com.mojang.logging.LogUtils;
import meteordevelopment.meteorclient.addons.MeteorAddon;
import meteordevelopment.meteorclient.commands.Commands;
+import meteordevelopment.meteorclient.systems.modules.Modules;
import org.slf4j.Logger;
public class Addon extends MeteorAddon {
@@ -16,7 +18,7 @@ public class Addon extends MeteorAddon {
LOG.info("Initializing Meteor Trash Addons");
// Modules
- //Modules.get().add(new ModuleExample());
+ Modules.get().add(new AutoTrade());
// Commands
Commands.add(new EntityDataCommand());
diff --git a/src/main/java/org/chrisoft/trashyaddon/mixin/MerchantScreenAccessor.java b/src/main/java/org/chrisoft/trashyaddon/mixin/MerchantScreenAccessor.java
new file mode 100644
index 0000000..8050ad3
--- /dev/null
+++ b/src/main/java/org/chrisoft/trashyaddon/mixin/MerchantScreenAccessor.java
@@ -0,0 +1,14 @@
+package org.chrisoft.trashyaddon.mixin;
+
+import net.minecraft.client.gui.screen.ingame.MerchantScreen;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(MerchantScreen.class)
+public interface MerchantScreenAccessor {
+ @Accessor("selectedIndex")
+ public void setSelectedIndex(int selectedIndex);
+ @Invoker("syncRecipeIndex")
+ public void invokeSyncRecipeIndex();
+}
diff --git a/src/main/java/org/chrisoft/trashyaddon/modules/AutoTrade.java b/src/main/java/org/chrisoft/trashyaddon/modules/AutoTrade.java
new file mode 100644
index 0000000..5cfacdc
--- /dev/null
+++ b/src/main/java/org/chrisoft/trashyaddon/modules/AutoTrade.java
@@ -0,0 +1,330 @@
+package org.chrisoft.trashyaddon.modules;
+
+import meteordevelopment.meteorclient.events.game.OpenScreenEvent;
+import meteordevelopment.meteorclient.events.packets.PacketEvent;
+import meteordevelopment.meteorclient.events.world.TickEvent;
+import meteordevelopment.meteorclient.settings.*;
+import meteordevelopment.meteorclient.systems.modules.Categories;
+import meteordevelopment.meteorclient.systems.modules.Module;
+import meteordevelopment.meteorclient.utils.player.FindItemResult;
+import meteordevelopment.meteorclient.utils.player.InvUtils;
+import meteordevelopment.orbit.EventHandler;
+import net.minecraft.client.gui.screen.ingame.MerchantScreen;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
+import net.minecraft.network.packet.s2c.play.SetTradeOffersS2CPacket;
+import net.minecraft.village.TradeOffer;
+import net.minecraft.village.TradeOfferList;
+import org.chrisoft.trashyaddon.mixin.MerchantScreenAccessor;
+
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Optional;
+
+public class AutoTrade extends Module {
+ private final SettingGroup sgGeneral = settings.getDefaultGroup();
+ private static final List<Item> allSellItems = List.of(
+ Items.COAL,
+ Items.CHICKEN,
+ Items.PORKCHOP,
+ Items.RABBIT,
+ Items.MUTTON,
+ Items.BEEF,
+ Items.DRIED_KELP_BLOCK,
+ Items.SWEET_BERRIES,
+ Items.IRON_INGOT,
+ Items.DIAMOND,
+ Items.PAPER,
+ Items.GLASS_PANE,
+ Items.ROTTEN_FLESH,
+ Items.GOLD_INGOT,
+ Items.RABBIT_FOOT,
+ Items.SCUTE,
+ Items.GLASS_BOTTLE,
+ Items.NETHER_WART,
+ Items.WHEAT,
+ Items.POTATO,
+ Items.CARROT,
+ Items.BEETROOT,
+ Items.PUMPKIN,
+ Items.MELON,
+ Items.STRING,
+ Items.COD,
+ Items.SALMON,
+ Items.TROPICAL_FISH,
+ Items.PUFFERFISH,
+ Items.STICK,
+ Items.FLINT,
+ Items.FEATHER,
+ Items.TRIPWIRE_HOOK,
+ Items.LEATHER,
+ Items.RABBIT_HIDE,
+ Items.BOOK,
+ Items.INK_SAC,
+ Items.CLAY_BALL,
+ Items.STONE,
+ Items.GRANITE,
+ Items.ANDESITE,
+ Items.DIORITE,
+ Items.QUARTZ
+ );
+
+ private static final List<Item> allBuyItems = List.of(
+ Items.BELL,
+ Items.COOKED_PORKCHOP,
+ Items.COOKED_CHICKEN,
+ Items.MAP,
+ Items.ITEM_FRAME,
+ Items.REDSTONE,
+ Items.LAPIS_LAZULI,
+ Items.GLOWSTONE,
+ Items.ENDER_PEARL,
+ Items.EXPERIENCE_BOTTLE,
+ Items.BREAD,
+ Items.PUMPKIN_PIE,
+ Items.APPLE,
+ Items.COOKIE,
+ Items.GOLDEN_CARROT,
+ Items.GLISTERING_MELON_SLICE,
+ Items.CAMPFIRE,
+ Items.ARROW,
+ Items.BOOKSHELF,
+ Items.LANTERN,
+ Items.GLASS,
+ Items.CLOCK,
+ Items.COMPASS,
+ Items.NAME_TAG,
+ Items.BRICK,
+ Items.CHISELED_STONE_BRICKS,
+ Items.DRIPSTONE_BLOCK,
+ Items.POLISHED_ANDESITE,
+ Items.POLISHED_DIORITE,
+ Items.POLISHED_GRANITE,
+ Items.QUARTZ_PILLAR,
+ Items.QUARTZ_BLOCK,
+ Items.PAINTING
+ );
+
+ private final Setting<List<Item>> sellsSetting = sgGeneral.add(new ItemListSetting.Builder()
+ .name("sells")
+ .description("Items to automatically SELL TO villagers.")
+ .filter((item) -> allSellItems.contains(item))
+ .build()
+ );
+ private final Setting<List<Item>> buysSetting = sgGeneral.add(new ItemListSetting.Builder()
+ .name("buys")
+ .description("Items to automatically BUY FROM villagers.")
+ .filter((item) -> allBuyItems.contains(item))
+ .build()
+ );
+ private final Setting<Integer> interactionRate = sgGeneral.add(new IntSetting.Builder()
+ .name("Interaction Rate")
+ .description("Number of ticks between interactions.")
+ .min(0)
+ .max(10)
+ .build()
+ );
+ private final Setting<Boolean> autoClose = sgGeneral.add(new BoolSetting.Builder()
+ .name("Auto Close")
+ .description("Close trading screen after any successful trades.")
+ .build()
+ );
+ private final Setting<Boolean> logSummary = sgGeneral.add(new BoolSetting.Builder()
+ .name("Log Summary")
+ .description("Give a summary of what has been traded once it finishes trading.")
+ .build()
+ );
+
+ private TradeOfferList offers;
+ private MerchantScreen screen;
+ private int currentOffer;
+ private int ticksRemaining;
+ private int countBefore;
+ private int countAfter;
+
+ private enum WaitState {
+ None,
+ WaitingForOutput,
+ WaitingForInventoryUpdate,
+ WaitingForFinalize
+ };
+ private WaitState waitState;
+ private ArrayList<ItemStack> itemsSold;
+ private ArrayList<ItemStack> itemsBought;
+
+
+ public AutoTrade() {
+ super(Categories.World, "Auto Trade", "Help prevent getting arthritis from excessively trading with villagers.");
+ itemsSold = new ArrayList<>();
+ itemsBought = new ArrayList<>();
+ waitState = WaitState.None;
+ }
+
+ /*
+ @Override
+ public String getInfoString() {
+ return waitState.toString() + " " + ticksRemaining;
+ }
+ */
+
+ private boolean isOfferEligible(TradeOffer o) {
+ // I don't give a SHIT to trades that use the second slot
+ // well actually I do, but I don't need THAT many enchanted books...
+ if (!o.getSecondBuyItem().getItem().equals(Items.AIR))
+ return false;
+ if (o.isDisabled())
+ return false;
+ ItemStack mbuy = o.getAdjustedFirstBuyItem();
+ ItemStack msell = o.getSellItem();
+ List<Item> sells = this.sellsSetting.get();
+ List<Item> buys = this.buysSetting.get();
+ if (!sells.contains(mbuy.getItem()) && !buys.contains(msell.getItem()))
+ return false;
+ FindItemResult rs = InvUtils.find((stack) -> stack.getItem().equals(mbuy.getItem()) && stack.getCount() >= mbuy.getCount());
+ if (!rs.found())
+ return false;
+ return true;
+ }
+
+ private void selectTrade() {
+ while (currentOffer < offers.size() && !isOfferEligible(offers.get(currentOffer)))
+ ++currentOffer;
+ if (currentOffer >= offers.size()) {
+ ticksRemaining = interactionRate.get();
+ waitState = WaitState.WaitingForFinalize;
+ return;
+ }
+ waitState = WaitState.WaitingForOutput;
+ ticksRemaining = -0xdead;
+ TradeOffer o = offers.get(currentOffer);
+ Item tradedItem = o.getSellItem().getItem().equals(Items.EMERALD) ?
+ o.getAdjustedFirstBuyItem().getItem() : o.getSellItem().getItem();
+ countBefore = screen.getScreenHandler().slots.stream()
+ .map(slot -> slot.getStack())
+ .filter(s -> s.getItem().equals(tradedItem))
+ .map(s -> s.getCount())
+ .reduce(0, Integer::sum);
+ ((MerchantScreenAccessor)screen).setSelectedIndex(currentOffer);
+ ((MerchantScreenAccessor)screen).invokeSyncRecipeIndex();
+ }
+
+ private void finalizeCurrentTrade() {
+ TradeOffer o = offers.get(currentOffer);
+ Item tradedItem = o.getSellItem().getItem().equals(Items.EMERALD) ?
+ o.getAdjustedFirstBuyItem().getItem() : o.getSellItem().getItem();
+ countAfter = screen.getScreenHandler().slots.stream()
+ .map(slot -> slot.getStack())
+ .filter(s -> s.getItem().equals(tradedItem))
+ .map(s -> s.getCount())
+ .reduce(0, Integer::sum);
+ ArrayList<ItemStack> itemsTraded = countAfter < countBefore ? itemsSold : itemsBought;
+ int count = java.lang.Math.abs(countAfter - countBefore);
+ Optional<ItemStack> t = itemsTraded.stream().filter(s -> s.getItem().equals(tradedItem)).findFirst();
+ if (t.isPresent()) {
+ t.get().setCount(t.get().getCount() + count);
+ }
+ else {
+ ItemStack s = new ItemStack(tradedItem, count);
+ itemsTraded.add(s);
+ }
+ }
+
+ private void endTrading() {
+ if (logSummary.get()) {
+ if (!itemsSold.isEmpty()) {
+ Formatter f = new Formatter();
+ f.format("Item(s) sold:");
+ boolean first = true;
+ for (ItemStack i : itemsSold) {
+ f.format("%s%s*%d", first ? " " : ", ", i.getName().getString(), i.getCount());
+ first = false;
+ }
+ info(f.toString());
+ }
+ if (!itemsBought.isEmpty()) {
+ Formatter f = new Formatter();
+ f.format("Item(s) bought:");
+ boolean first = true;
+ for (ItemStack i : itemsBought) {
+ f.format("%s%s*%d", first ? " " : ", ", i.getName().getString(), i.getCount());
+ first = false;
+ }
+ info(f.toString());
+ }
+ }
+ if (autoClose.get() && (!itemsBought.isEmpty() || !itemsSold.isEmpty()))
+ screen.close();
+ screen = null;
+ }
+ @EventHandler
+ private void onTick(TickEvent.Pre event) {
+ if (ticksRemaining > 0) {
+ --ticksRemaining;
+ return;
+ }
+ if (offers != null && screen != null) {
+ if (waitState == WaitState.WaitingForFinalize) {
+ endTrading();
+ return;
+ }
+ if (waitState != WaitState.None && currentOffer < offers.size() && offers.get(currentOffer).isDisabled()) {
+ finalizeCurrentTrade();
+ waitState = WaitState.None;
+ ticksRemaining = interactionRate.get();
+ return;
+ }
+ if (ticksRemaining == -0xdead)
+ return;
+ switch (waitState) {
+ case None: selectTrade(); break;
+ case WaitingForOutput:
+ InvUtils.shiftClick().slotId(2);
+ waitState = WaitState.WaitingForInventoryUpdate;
+ ticksRemaining = -0xdead;
+ break;
+ case WaitingForInventoryUpdate:
+ finalizeCurrentTrade();
+ waitState = WaitState.None;
+ ticksRemaining = interactionRate.get();
+ break;
+ }
+ }
+ }
+
+ @EventHandler
+ private void onReceivePacket(PacketEvent.Receive e) {
+ if (e.packet instanceof SetTradeOffersS2CPacket p) {
+ this.offers = p.getOffers();
+ currentOffer = 0;
+ waitState = WaitState.None;
+ ticksRemaining = 0;
+ itemsSold.clear();
+ itemsBought.clear();
+ } else if (e.packet instanceof ScreenHandlerSlotUpdateS2CPacket p) {
+ if (screen == null || p.getSyncId() != screen.getScreenHandler().syncId || p.getSlot() != 2)
+ return;
+ if (waitState == WaitState.WaitingForOutput) {
+ ticksRemaining = interactionRate.get();
+ }
+ if (waitState == WaitState.WaitingForInventoryUpdate) {
+ if (!p.getStack().isEmpty())
+ waitState = WaitState.WaitingForOutput;
+ ticksRemaining = interactionRate.get();
+ }
+ }
+ }
+
+ @EventHandler
+ private void onOpenScreen(OpenScreenEvent e) {
+ if (e.screen == null) {
+ this.screen = null;
+ this.offers = null;
+ }
+ else if (e.screen instanceof MerchantScreen s) {
+ this.screen = s;
+ }
+ }
+}
diff --git a/src/main/resources/addon.mixins.json b/src/main/resources/addon.mixins.json
index 7fbd83d..9ddc8ba 100644
--- a/src/main/resources/addon.mixins.json
+++ b/src/main/resources/addon.mixins.json
@@ -2,7 +2,9 @@
"required": true,
"package": "org.chrisoft.trashyaddon.mixin",
"compatibilityLevel": "JAVA_17",
- "client": [],
+ "client": [
+ "MerchantScreenAccessor"
+ ],
"injectors": {
"defaultRequire": 1
}
diff --git a/src/main/resources/assets/template/icon.png b/src/main/resources/assets/template/icon.png
index 3fb2e7f..2684041 100644
--- a/src/main/resources/assets/template/icon.png
+++ b/src/main/resources/assets/template/icon.png
Binary files differ