diff --git a/README.md b/README.md
index c636741..a60e4da 100644
--- a/README.md
+++ b/README.md
@@ -30,12 +30,12 @@ You can also use Tab and Shift+Tab to cycle through available screens.
- Fits on-screen with [EMI](https://modrinth.com/mod/emi), even on very high GUI scales - Use `Left (Compressed)` effects.
-#### Anti-Cheat & Convenience
+#### Anti-Cheat & Fairness
Inventory Tabs 4 offers no guarantees or defence against server moderation or anti-cheat - tabs provide an unfair advantage, and look outwardly suspicious to onlookers in multiplayer.
-In fact, some fully non-vanilla actions are possible for convenience, such as:
- - Accessing your full regular inventory while riding a horse or chest boat.
- - Accessing sneak-interact inventories without dismounting from a vehicle.
+Notably, the mod allows some usually impossible actions for the sake of convenience, e.g.
+ - The full player inventory can be accessed while riding a horse or chest boat.
+ - Sneak-interact inventories can be accessed without dismounting from a vehicle.
---
diff --git a/gradle.properties b/gradle.properties
index 91e7379..8242505 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,6 +7,6 @@ org.gradle.configureondemand=true
# Enable advanced multi-module optimizations (share tiny-remaper instance between projects)
fabric.loom.multiProjectOptimisation=true
# Mod Properties
-baseVersion = 1.2.0
+baseVersion = 1.3.0
defaultBranch = 1.20
branch = 1.20
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index db9a6b8..17655d0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/libs.versions.toml b/libs.versions.toml
index 4cd782d..1e39131 100644
--- a/libs.versions.toml
+++ b/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-loom = "1.4.+"
+loom = "1.6.+"
githubRelease = "2.4.1"
minotaur = "2.6.0"
diff --git a/src/main/java/folk/sisby/inventory_tabs/InventoryTabsConfig.java b/src/main/java/folk/sisby/inventory_tabs/InventoryTabsConfig.java
index 018f3e1..6bf6ef7 100644
--- a/src/main/java/folk/sisby/inventory_tabs/InventoryTabsConfig.java
+++ b/src/main/java/folk/sisby/inventory_tabs/InventoryTabsConfig.java
@@ -39,6 +39,9 @@ public class InventoryTabsConfig extends WrappedConfig {
@Comment("Whether to show tabs on screens that aren't specified below")
public final Boolean allowScreensByDefault = true;
+ @Comment("Whether to show tabs on the bottom of screens that aren't specified below")
+ public final Boolean invertTabsByDefault = false;
+
@Comment("")
@Comment("-------------------------------")
@Comment("")
@@ -55,7 +58,7 @@ public class InventoryTabsConfig extends WrappedConfig {
@Comment("Positive values expand the left boundary, allowing more tabs to be drawn")
@Comment("null means the player inventory")
@Comment("")
- public final Map leftBoundOffsetOverride = ValueMap.builder(0).put("null", 0).build();
+ public final Map leftBoundOffsetOverride = ValueMap.builder(0).put("minecraft:loom", 0).build();
@Comment("")
@Comment("-------------------------------")
@@ -64,7 +67,16 @@ public class InventoryTabsConfig extends WrappedConfig {
@Comment("Positive values expand the right boundary, allowing more tabs to be drawn")
@Comment("null means the player inventory")
@Comment("")
- public final Map rightBoundOffsetOverride = ValueMap.builder(0).put("null", 0).build();
+ public final Map rightBoundOffsetOverride = ValueMap.builder(0).put("minecraft:loom", 0).build();
+
+ @Comment("")
+ @Comment("-------------------------------")
+ @Comment("")
+ @Comment("Manually choose where to place tabs on a given screen")
+ @Comment("false means above, true means below")
+ @Comment("null key means the player inventory")
+ @Comment("")
+ public final Map invertedTabsOverride = ValueMap.builder(false).put("minecraft:beacon", false).build();
@Comment("")
@Comment("-------------------------------")
diff --git a/src/main/java/folk/sisby/inventory_tabs/ScreenSupport.java b/src/main/java/folk/sisby/inventory_tabs/ScreenSupport.java
index 77e2cec..5aa6833 100644
--- a/src/main/java/folk/sisby/inventory_tabs/ScreenSupport.java
+++ b/src/main/java/folk/sisby/inventory_tabs/ScreenSupport.java
@@ -19,6 +19,7 @@ public class ScreenSupport {
public static Map>> DENY = new HashMap<>();
public static Map>> ALLOW = new HashMap<>();
public static Map> SCREEN_BOUND_OFFSETS = new HashMap<>();
+ public static Map SCREEN_INVERTS = new HashMap<>();
public static Boolean allowTabs(RegistryKey> type) {
if (InventoryTabs.CONFIG.screenOverrides.entrySet().stream().filter(e -> !e.getValue()).anyMatch(e -> Objects.equals(e.getKey(), type.getValue().toString()))) return false;
@@ -48,5 +49,6 @@ public static boolean allowTabs(Screen screen) {
ALLOW.put(InventoryTabs.id("horse_screen"), hs -> hs instanceof HorseScreen);
InventoryTabs.CONFIG.leftBoundOffsetOverride.forEach((screenHandlerId, offset) -> SCREEN_BOUND_OFFSETS.put(screenHandlerId.equals("null") ? null : new Identifier(screenHandlerId), new Pair<>(offset, 0)));
InventoryTabs.CONFIG.rightBoundOffsetOverride.forEach((screenHandlerId, offset) -> SCREEN_BOUND_OFFSETS.merge(screenHandlerId.equals("null") ? null : new Identifier(screenHandlerId), new Pair<>(0, offset), (o, n) -> new Pair<>(o.getLeft(), n.getRight())));
+ InventoryTabs.CONFIG.invertedTabsOverride.forEach((screenHandlerId, doInvert) -> SCREEN_INVERTS.put(screenHandlerId.equals("null") ? null : new Identifier(screenHandlerId), doInvert));
}
}
diff --git a/src/main/java/folk/sisby/inventory_tabs/duck/InventoryTabsScreen.java b/src/main/java/folk/sisby/inventory_tabs/duck/InventoryTabsScreen.java
index b124405..f0b5389 100644
--- a/src/main/java/folk/sisby/inventory_tabs/duck/InventoryTabsScreen.java
+++ b/src/main/java/folk/sisby/inventory_tabs/duck/InventoryTabsScreen.java
@@ -1,5 +1,6 @@
package folk.sisby.inventory_tabs.duck;
+import folk.sisby.inventory_tabs.InventoryTabs;
import folk.sisby.inventory_tabs.ScreenSupport;
import folk.sisby.inventory_tabs.util.WidgetPosition;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
@@ -18,6 +19,7 @@ default List getTabPositions(int tabWidth) {
List list = new ArrayList<>();
Identifier screenHandlerId = Registries.SCREEN_HANDLER.getId(screen.getScreenHandler().type);
Pair offsets = ScreenSupport.SCREEN_BOUND_OFFSETS.getOrDefault(screenHandlerId, new Pair<>(0,0));
+ boolean invert = ScreenSupport.SCREEN_INVERTS.getOrDefault(screenHandlerId, InventoryTabs.CONFIG.invertTabsByDefault);
int width = screen.backgroundWidth + offsets.getLeft() + offsets.getRight();
int left = Math.max(screen.x - offsets.getLeft(), 0);
@@ -25,7 +27,7 @@ default List getTabPositions(int tabWidth) {
int margins = width - tabWidth * count;
for (int i = 0; i < count; i++) {
- list.add(new WidgetPosition(left + margins / 2 + i * tabWidth, screen.y, true));
+ list.add(new WidgetPosition(left + margins / 2 + i * tabWidth, invert ? screen.y + screen.backgroundHeight : screen.y, !invert));
}
return list;
diff --git a/src/main/java/folk/sisby/inventory_tabs/tabs/Tab.java b/src/main/java/folk/sisby/inventory_tabs/tabs/Tab.java
index 9598e27..caa21f2 100644
--- a/src/main/java/folk/sisby/inventory_tabs/tabs/Tab.java
+++ b/src/main/java/folk/sisby/inventory_tabs/tabs/Tab.java
@@ -16,16 +16,13 @@
public interface Tab {
Identifier TABS_TEXTURE = new Identifier("textures/gui/container/creative_inventory/tabs.png");
- int TAB_INSET_HEIGHT_SELECTED = 4;
- int TAB_INSET_HEIGHT_UNSELECTED = 0;
- int TAB_TEXTURE_WIDTH = 26;
- int TAB_TEXTURE_HEIGHT_SELECTED = 32;
- int TAB_TEXTURE_HEIGHT_UNSELECTED = 30;
- int TAB_TEXTURE_U = 26;
- int TAB_TEXTURE_V_UNSELECTED = 2;
- int TAB_TEXTURE_V_UNSELECTED_INVERTED = 64;
- int TAB_TEXTURE_V_SELECTED = 32;
- int TAB_TEXTURE_V_SELECTED_INVERTED = 96;
+ int TEXTURE_WIDTH = 26;
+ int TEXTURE_U = 26;
+ int[] TEXTURE_V = new int[]{2, 32, 64, 96};
+ int[] TEXTURE_HEIGHT = new int[]{30, 32, 28, 32};
+ int[] Y_OFFSET = new int[]{0, 0, 0, -4};
+ int[] ITEM_Y_OFFSET = new int[]{0, 0, -3, -3};
+ int[] HEIGHT_OFFSET = new int[]{0, 4, 0, 4};
/**
* Opens the screen associated with the tab.
@@ -50,7 +47,8 @@ public interface Tab {
/**
* Called when the screen associated with the tab is closed (for handlers that aren't destroyed when closed on the servers)
*/
- default void close(ClientPlayerEntity player, ClientWorld world, ScreenHandler handler, ClientPlayerInteractionManager interactionManager) {}
+ default void close(ClientPlayerEntity player, ClientWorld world, ScreenHandler handler, ClientPlayerInteractionManager interactionManager) {
+ }
/**
* @return the tab's left-priority when being displayed. The player's inventory is at 100.
@@ -63,23 +61,29 @@ default int getPriority() {
* @return whether the tabs open method instantly opens the screen on the client side without slot sync.
* Used for the survival inventory. Helps preserve cursor stacks.
*/
- default boolean isInstant() { return false; }
+ default boolean isInstant() {
+ return false;
+ }
/**
* @return whether the tab can only be safely opened through the player inventory screen.
* Helps prevent lockups, but might flicker.
*/
- default boolean isBuffered() { return false; }
+ default boolean isBuffered() {
+ return false;
+ }
default void render(DrawContext drawContext, WidgetPosition pos, int width, int height, double mouseX, double mouseY, boolean current) {
- int y = pos.y + (pos.up ? -height : height);
- int drawHeight = height + (current ? TAB_INSET_HEIGHT_SELECTED : TAB_INSET_HEIGHT_UNSELECTED);
- int textureHeight = current ? TAB_TEXTURE_HEIGHT_SELECTED : TAB_TEXTURE_HEIGHT_UNSELECTED;
- int v = current ? (pos.up ? TAB_TEXTURE_V_SELECTED : TAB_TEXTURE_V_SELECTED_INVERTED) : (pos.up ? TAB_TEXTURE_V_UNSELECTED : TAB_TEXTURE_V_UNSELECTED_INVERTED);
- DrawUtil.drawCrunched(drawContext, TABS_TEXTURE, pos.x, y, width, drawHeight, TAB_TEXTURE_WIDTH, textureHeight, TAB_TEXTURE_U, v);
+ int type = pos.up ? (!current ? 0 : 1) : (!current ? 2 : 3);
+ int y = pos.y + (pos.up ? -height : 0);
+ int drawHeight = height + HEIGHT_OFFSET[type];
+ int drawY = y + Y_OFFSET[type];
+ DrawUtil.drawCrunched(drawContext, TABS_TEXTURE, pos.x, drawY, width, drawHeight, TEXTURE_WIDTH, TEXTURE_HEIGHT[type], TEXTURE_U, TEXTURE_V[type]);
int itemPadding = Math.max(0, (width - 16) / 2);
- drawContext.drawItem(getTabIcon(), pos.x + itemPadding, y + itemPadding);
- if (new Rect2i(pos.x + itemPadding, y + itemPadding, 16, 16).contains((int) mouseX, (int) mouseY)) {
+ int itemX = pos.x + itemPadding;
+ int itemY = y + itemPadding + ITEM_Y_OFFSET[type];
+ drawContext.drawItem(getTabIcon(), itemX, itemY);
+ if (new Rect2i(itemX, itemY, 16, 16).contains((int) mouseX, (int) mouseY)) {
drawContext.drawTooltip(MinecraftClient.getInstance().textRenderer, getHoverText(), (int) mouseX, (int) mouseY);
}
}