diff --git a/build.gradle b/build.gradle index b36b7bcf..d83aaed1 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'fabric-loom' version '1.2-SNAPSHOT' id 'maven-publish' - id 'io.github.juuxel.loom-quiltflower' version '1.10.0' + id 'io.github.juuxel.loom-vineflower' version '1.11.0' } allprojects { @@ -128,7 +128,7 @@ dependencies { modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:${project.rei_version}") modCompileOnly("dev.emi:emi-fabric:${project.emi_version}") - modLocalRuntime("dev.emi:emi-fabric:${project.emi_version}") +// modLocalRuntime("dev.emi:emi-fabric:${project.emi_version}") modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}") modLocalRuntime("com.terraformersmc:modmenu:${project.modmenu_version}") diff --git a/gradle.properties b/gradle.properties index 4ee2cb08..04fe17a9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,28 +2,28 @@ org.gradle.jvmargs=-Xmx2G # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_base_version=1.20 -minecraft_version=1.20.1 -yarn_mappings=1.20.1+build.2 -loader_version=0.14.21 +minecraft_base_version=1.20.2 +minecraft_version=1.20.2 +yarn_mappings=1.20.2+build.1 +loader_version=0.14.22 # Mod Properties -mod_version=0.11.2-pre.14 +mod_version=0.11.3 maven_group=io.wispforest archives_base_name=owo-lib # Dependencies -fabric_version=0.85.0+1.20.1 +fabric_version=0.89.2+1.20.2 # https://maven.shedaniel.me/me/shedaniel/RoughlyEnoughItems-fabric/ -rei_version=12.0.625 +rei_version=13.0.661 -# https://maven.terraformersmc.com/releases/dev/emi/emi/ -emi_version=1.0.3+1.20 +# https://maven.terraformersmc.com/releases/dev/emi/emi-fabric/ +emi_version=1.0.19+1.20.1 # https://search.maven.org/artifact/blue.endless/jankson jankson_version=1.2.2 # https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu -modmenu_version=7.0.1 +modmenu_version=8.0.0 -# https://maven.nucleoid.xyz/fr/catcore/server-translations-api/ +# https://maven.nucleoid.xyz/xyz/nucleoid/server-translations-api/ stapi_version=2.0.0+1.20 diff --git a/src/main/java/io/wispforest/owo/compat/rei/ReiUIAdapter.java b/src/main/java/io/wispforest/owo/compat/rei/ReiUIAdapter.java index 6bae0608..d5a99d47 100644 --- a/src/main/java/io/wispforest/owo/compat/rei/ReiUIAdapter.java +++ b/src/main/java/io/wispforest/owo/compat/rei/ReiUIAdapter.java @@ -63,8 +63,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return this.adapter.mouseScrolled(mouseX - this.adapter.x(), mouseY - this.adapter.y(), amount); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + return this.adapter.mouseScrolled(mouseX - this.adapter.x(), mouseY - this.adapter.y(), horizontalAmount, verticalAmount); } @Override diff --git a/src/main/java/io/wispforest/owo/compat/rei/ReiWidgetComponent.java b/src/main/java/io/wispforest/owo/compat/rei/ReiWidgetComponent.java index b19f3826..476780a5 100644 --- a/src/main/java/io/wispforest/owo/compat/rei/ReiWidgetComponent.java +++ b/src/main/java/io/wispforest/owo/compat/rei/ReiWidgetComponent.java @@ -86,7 +86,7 @@ public boolean onMouseUp(double mouseX, double mouseY, int button) { @Override public boolean onMouseScroll(double mouseX, double mouseY, double amount) { - return this.widget.mouseScrolled(this.x + mouseX, this.y + mouseY, amount) + return this.widget.mouseScrolled(this.x + mouseX, this.y + mouseY, 0, amount) | super.onMouseScroll(mouseX, mouseY, amount); } diff --git a/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java b/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java index e6645f62..e1f28347 100644 --- a/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java +++ b/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java @@ -2,7 +2,7 @@ import com.google.common.collect.HashMultimap; import io.wispforest.owo.Owo; -import io.wispforest.owo.mixin.ServerPlayNetworkHandlerAccessor; +import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor; import io.wispforest.owo.ops.TextOps; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -56,7 +56,7 @@ static void register(ConfigWrapper config) { * or {@code null} if no config with the given name was synced */ public static @Nullable Map getClientOptions(ServerPlayerEntity player, String configName) { - var storage = CLIENT_OPTION_STORAGE.get(((ServerPlayNetworkHandlerAccessor) player.networkHandler).owo$getConnection()); + var storage = CLIENT_OPTION_STORAGE.get(((ServerCommonNetworkHandlerAccessor) player.networkHandler).owo$getConnection()); if (storage == null) return null; return storage.get(configName); @@ -188,7 +188,7 @@ private static void applyClient(MinecraftClient client, ClientPlayNetworkHandler private static void applyServer(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender sender) { Owo.LOGGER.info("Receiving client config"); - var connection = ((ServerPlayNetworkHandlerAccessor) player.networkHandler).owo$getConnection(); + var connection = ((ServerCommonNetworkHandlerAccessor) player.networkHandler).owo$getConnection(); read(buf, (option, optionBuf) -> { var config = CLIENT_OPTION_STORAGE.computeIfAbsent(connection, $ -> new HashMap<>()).computeIfAbsent(option.configName(), s -> new HashMap<>()); diff --git a/src/main/java/io/wispforest/owo/config/ui/component/ListOptionContainer.java b/src/main/java/io/wispforest/owo/config/ui/component/ListOptionContainer.java index d454967f..91fed89e 100644 --- a/src/main/java/io/wispforest/owo/config/ui/component/ListOptionContainer.java +++ b/src/main/java/io/wispforest/owo/config/ui/component/ListOptionContainer.java @@ -124,7 +124,7 @@ protected void refreshOptions() { final var box = new ConfigTextBox(); box.setText(this.backingList.get(i).toString()); - box.setCursorToStart(); + box.setCursorToStart(false); box.setDrawsBackground(false); box.margins(Insets.vertical(2)); box.horizontalSizing(Sizing.fill(95)); diff --git a/src/main/java/io/wispforest/owo/itemgroup/OwoItemGroup.java b/src/main/java/io/wispforest/owo/itemgroup/OwoItemGroup.java index 3787a7f3..85d5e217 100644 --- a/src/main/java/io/wispforest/owo/itemgroup/OwoItemGroup.java +++ b/src/main/java/io/wispforest/owo/itemgroup/OwoItemGroup.java @@ -52,20 +52,25 @@ public abstract class OwoItemGroup extends ItemGroup { private final IntSet activeTabsView = IntSets.unmodifiable(this.activeTabs); private boolean initialized = false; + private final @Nullable Identifier backgroundTexture; + private final @Nullable ScrollerTextures scrollerTextures; + private final @Nullable TabTextures tabTextures; + private final int tabStackHeight; private final int buttonStackHeight; - private final Identifier customTexture; private final boolean useDynamicTitle; private final boolean displaySingleTab; private final boolean allowMultiSelect; - protected OwoItemGroup(Identifier id, Consumer initializer, Supplier iconSupplier, int tabStackHeight, int buttonStackHeight, @Nullable Identifier customTexture, boolean useDynamicTitle, boolean displaySingleTab, boolean allowMultiSelect) { + protected OwoItemGroup(Identifier id, Consumer initializer, Supplier iconSupplier, int tabStackHeight, int buttonStackHeight, @Nullable Identifier backgroundTexture, @Nullable ScrollerTextures scrollerTextures, @Nullable TabTextures tabTextures, boolean useDynamicTitle, boolean displaySingleTab, boolean allowMultiSelect) { super(null, -1, Type.CATEGORY, Text.translatable("itemGroup.%s.%s".formatted(id.getNamespace(), id.getPath())), () -> ItemStack.EMPTY, (displayContext, entries) -> {}); this.initializer = initializer; this.iconSupplier = iconSupplier; this.tabStackHeight = tabStackHeight; this.buttonStackHeight = buttonStackHeight; - this.customTexture = customTexture; + this.backgroundTexture = backgroundTexture; + this.scrollerTextures = scrollerTextures; + this.tabTextures = tabTextures; this.useDynamicTitle = useDynamicTitle; this.displaySingleTab = displaySingleTab; this.allowMultiSelect = allowMultiSelect; @@ -308,8 +313,16 @@ public boolean isTabSelected(int tab) { return this.activeTabs.contains(tab); } - public Identifier getCustomTexture() { - return customTexture; + public @Nullable Identifier getBackgroundTexture() { + return this.backgroundTexture; + } + + public @Nullable ScrollerTextures getScrollerTextures() { + return this.scrollerTextures; + } + + public @Nullable TabTextures getTabTextures() { + return this.tabTextures; } public int getTabStackHeight() { @@ -363,7 +376,9 @@ public static class Builder { private Consumer initializer = owoItemGroup -> {}; private int tabStackHeight = 4; private int buttonStackHeight = 4; - private @Nullable Identifier customTexture = null; + private @Nullable Identifier backgroundTexture = null; + private @Nullable ScrollerTextures scrollerTextures = null; + private @Nullable TabTextures tabTextures = null; private boolean useDynamicTitle = true; private boolean displaySingleTab = false; private boolean allowMultiSelect = true; @@ -388,8 +403,18 @@ public Builder buttonStackHeight(int buttonStackHeight) { return this; } - public Builder customTexture(@Nullable Identifier customTexture) { - this.customTexture = customTexture; + public Builder backgroundTexture(@Nullable Identifier backgroundTexture) { + this.backgroundTexture = backgroundTexture; + return this; + } + + public Builder scrollerTextures(ScrollerTextures scrollerTextures) { + this.scrollerTextures = scrollerTextures; + return this; + } + + public Builder tabTextures(TabTextures tabTextures) { + this.tabTextures = tabTextures; return this; } @@ -409,7 +434,7 @@ public Builder withoutMultipleSelection() { } public OwoItemGroup build() { - final var group = new OwoItemGroup(id, initializer, iconSupplier, tabStackHeight, buttonStackHeight, customTexture, useDynamicTitle, displaySingleTab, allowMultiSelect) {}; + final var group = new OwoItemGroup(id, initializer, iconSupplier, tabStackHeight, buttonStackHeight, backgroundTexture, scrollerTextures, tabTextures, useDynamicTitle, displaySingleTab, allowMultiSelect) {}; Registry.register(Registries.ITEM_GROUP, this.id, group); return group; } @@ -428,6 +453,9 @@ public void add(ItemStack stack, StackVisibility visibility) { } } + public record ScrollerTextures(Identifier enabled, Identifier disabled) {} + public record TabTextures(Identifier topSelected, Identifier topSelectedFirstColumn, Identifier topUnselected, Identifier bottomSelected, Identifier bottomSelectedFirstColumn, Identifier bottomUnselected) {} + // Utility /** diff --git a/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java b/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java index f8dac27c..182c4a56 100644 --- a/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java +++ b/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java @@ -8,10 +8,10 @@ import io.wispforest.owo.mixin.itemgroup.ItemGroupAccessor; import io.wispforest.owo.mixin.ui.SimpleRegistryAccessor; import net.minecraft.item.ItemGroup; -import net.minecraft.registry.MutableRegistry; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.SimpleRegistry; import net.minecraft.util.Identifier; import org.jetbrains.annotations.ApiStatus; @@ -30,13 +30,13 @@ public class WrapperGroup extends OwoItemGroup { @SuppressWarnings("unchecked") public WrapperGroup(ItemGroup parent, Identifier parentId, List tabs, List buttons) { - super(parentId, owoItemGroup -> {}, () -> Icon.of(parent.getIcon()), 4, 4, null, true, false, false); + super(parentId, owoItemGroup -> {}, () -> Icon.of(parent.getIcon()), 4, 4, null, null, null, true, false, false); int parentRawId = Registries.ITEM_GROUP.getRawId(parent); ((SimpleRegistryAccessor) Registries.ITEM_GROUP).owo$getValueToEntry().remove(parent); ((SimpleRegistryAccessor) Registries.ITEM_GROUP).owo$getEntryToLifecycle().remove(parent); - ((MutableRegistry) Registries.ITEM_GROUP).set(parentRawId, RegistryKey.of(RegistryKeys.ITEM_GROUP, parentId), this, Lifecycle.stable()); + ((SimpleRegistry) Registries.ITEM_GROUP).set(parentRawId, RegistryKey.of(RegistryKeys.ITEM_GROUP, parentId), this, Lifecycle.stable()); ((ItemGroupAccessor) this).owo$setDisplayName(parent.getDisplayName()); ((ItemGroupAccessor) this).owo$setColumn(parent.getColumn()); diff --git a/src/main/java/io/wispforest/owo/mixin/ClientCommonNetworkHandlerAccessor.java b/src/main/java/io/wispforest/owo/mixin/ClientCommonNetworkHandlerAccessor.java new file mode 100644 index 00000000..c054de04 --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/ClientCommonNetworkHandlerAccessor.java @@ -0,0 +1,12 @@ +package io.wispforest.owo.mixin; + +import net.minecraft.client.network.ClientCommonNetworkHandler; +import net.minecraft.network.ClientConnection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ClientCommonNetworkHandler.class) +public interface ClientCommonNetworkHandlerAccessor { + @Accessor + ClientConnection getConnection(); +} diff --git a/src/main/java/io/wispforest/owo/mixin/ServerPlayNetworkHandlerAccessor.java b/src/main/java/io/wispforest/owo/mixin/ServerCommonNetworkHandlerAccessor.java similarity index 66% rename from src/main/java/io/wispforest/owo/mixin/ServerPlayNetworkHandlerAccessor.java rename to src/main/java/io/wispforest/owo/mixin/ServerCommonNetworkHandlerAccessor.java index aa2dd185..c49f5fcf 100644 --- a/src/main/java/io/wispforest/owo/mixin/ServerPlayNetworkHandlerAccessor.java +++ b/src/main/java/io/wispforest/owo/mixin/ServerCommonNetworkHandlerAccessor.java @@ -1,12 +1,13 @@ package io.wispforest.owo.mixin; import net.minecraft.network.ClientConnection; +import net.minecraft.server.network.ServerCommonNetworkHandler; import net.minecraft.server.network.ServerPlayNetworkHandler; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(ServerPlayNetworkHandler.class) -public interface ServerPlayNetworkHandlerAccessor { +@Mixin(ServerCommonNetworkHandler.class) +public interface ServerCommonNetworkHandlerAccessor { @Accessor("connection") ClientConnection owo$getConnection(); diff --git a/src/main/java/io/wispforest/owo/mixin/ServerLoginNetworkHandlerAccessor.java b/src/main/java/io/wispforest/owo/mixin/ServerLoginNetworkHandlerAccessor.java deleted file mode 100644 index 476a393e..00000000 --- a/src/main/java/io/wispforest/owo/mixin/ServerLoginNetworkHandlerAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.wispforest.owo.mixin; - -import net.minecraft.network.ClientConnection; -import net.minecraft.server.network.ServerLoginNetworkHandler; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(ServerLoginNetworkHandler.class) -public interface ServerLoginNetworkHandlerAccessor { - - @Accessor("connection") - ClientConnection owo$getConnection(); - -} diff --git a/src/main/java/io/wispforest/owo/mixin/itemgroup/CreativeInventoryScreenMixin.java b/src/main/java/io/wispforest/owo/mixin/itemgroup/CreativeInventoryScreenMixin.java index 475eae5f..fffabb8e 100644 --- a/src/main/java/io/wispforest/owo/mixin/itemgroup/CreativeInventoryScreenMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/itemgroup/CreativeInventoryScreenMixin.java @@ -16,6 +16,7 @@ import net.minecraft.resource.featuretoggle.FeatureSet; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -43,18 +44,24 @@ public abstract class CreativeInventoryScreenMixin extends AbstractInventoryScre @Shadow protected abstract boolean shouldShowOperatorTab(PlayerEntity player); + @Shadow + protected abstract boolean hasScrollbar(); + + @Unique + private @Nullable OwoItemGroup contextGroup = null; + @Unique - private final List owo$buttons = new ArrayList<>(); + private final List owoButtons = new ArrayList<>(); @Unique - private FeatureSet owo$enabledFeatures = null; + private FeatureSet enabledFeatures = null; @Unique - private final CursorAdapter owo$cursorAdapter = CursorAdapter.ofClientWindow(); + private final CursorAdapter cursorAdapter = CursorAdapter.ofClientWindow(); @Inject(method = "", at = @At("TAIL")) private void captureFeatures(PlayerEntity player, FeatureSet enabledFeatures, boolean operatorTabEnabled, CallbackInfo ci) { - this.owo$enabledFeatures = enabledFeatures; + this.enabledFeatures = enabledFeatures; } // ---------- @@ -63,46 +70,51 @@ private void captureFeatures(PlayerEntity player, FeatureSet enabledFeatures, bo @ModifyArg(method = "drawBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lnet/minecraft/util/Identifier;IIIIII)V", ordinal = 0)) private Identifier injectCustomGroupTexture(Identifier original) { - if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getCustomTexture() == null) return original; - return owoGroup.getCustomTexture(); + if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getBackgroundTexture() == null) return original; + return owoGroup.getBackgroundTexture(); } // ---------------- // Scrollbar slider // ---------------- - @ModifyArgs(method = "drawBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lnet/minecraft/util/Identifier;IIIIII)V", ordinal = 1)) + @ModifyArgs(method = "drawBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) private void injectCustomScrollbarTexture(Args args) { - if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getCustomTexture() == null) return; + if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getScrollerTextures() == null) return; - args.set(0, owoGroup.getCustomTexture()); - args.set(3, args.get(3) - 232); - args.set(4, 136); + args.set(0, this.hasScrollbar() ? owoGroup.getScrollerTextures().enabled() : owoGroup.getScrollerTextures().disabled()); } // ------------- // Group headers // ------------- - @ModifyArg(method = "renderTabIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lnet/minecraft/util/Identifier;IIIIII)V")) - private Identifier injectCustomTabTexture(Identifier texture) { - if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getCustomTexture() == null) return texture; - return owoGroup.getCustomTexture(); + @Inject(method = "renderTabIcon", at = @At("HEAD")) + private void captureContextGroup(DrawContext context, ItemGroup group, CallbackInfo ci) { + if (group instanceof OwoItemGroup owoGroup) { + this.contextGroup = owoGroup; + } else { + this.contextGroup = null; + } } - @ModifyArg(method = "renderTabIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lnet/minecraft/util/Identifier;IIIIII)V"), index = 3) - private int injectCustomTabTextureLocation(int original) { - if (!(selectedTab instanceof OwoItemGroup owoGroup) || owoGroup.getCustomTexture() == null) return original; - return owoGroup.getColumn() == 0 ? 195 : 221; + @ModifyArg(method = "renderTabIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) + private Identifier injectCustomTabTexture(Identifier texture) { + if (this.contextGroup == null || this.contextGroup.getTabTextures() == null) return texture; + + var textures = this.contextGroup.getTabTextures(); + return this.contextGroup.getRow() == ItemGroup.Row.TOP + ? selectedTab == this.contextGroup ? this.contextGroup.getColumn() == 0 ? textures.topSelectedFirstColumn() : textures.topSelected() : textures.topUnselected() + : selectedTab == this.contextGroup ? this.contextGroup.getColumn() == 0 ? textures.bottomSelectedFirstColumn() : textures.bottomSelected() : textures.bottomUnselected(); } @Inject(method = "renderTabIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemGroup;getIcon()Lnet/minecraft/item/ItemStack;"), locals = LocalCapture.CAPTURE_FAILHARD) - private void renderOwoIcon(DrawContext context, ItemGroup group, CallbackInfo ci, boolean bl, boolean bl2, int i, int j, int k, int l, int m) { + private void renderOwoIcon(DrawContext context, ItemGroup group, CallbackInfo ci, boolean bl, boolean bl2, int i, int j, int k) { if (!(group instanceof OwoItemGroup owoGroup)) return; RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); - owoGroup.icon().render(context, l, m, 0, 0, 0); + owoGroup.icon().render(context, j, k, 0, 0, 0); RenderSystem.disableBlend(); } @@ -112,7 +124,9 @@ private void renderOwoIcon(DrawContext context, ItemGroup group, CallbackInfo ci @ModifyArg(method = "drawForeground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)I")) private Text injectTabNameAsTitle(Text original) { - if (!(selectedTab instanceof OwoItemGroup owoGroup) || !owoGroup.hasDynamicTitle() || owoGroup.selectedTabs().size() != 1) return original; + if (!(selectedTab instanceof OwoItemGroup owoGroup) || !owoGroup.hasDynamicTitle() || owoGroup.selectedTabs().size() != 1) { + return original; + } var singleActiveTab = owoGroup.getTab(owoGroup.selectedTabs().iterator().nextInt()); if (singleActiveTab.primary()) { @@ -132,8 +146,8 @@ private Text injectTabNameAsTitle(Text original) { @Inject(at = @At("HEAD"), method = "setSelectedTab(Lnet/minecraft/item/ItemGroup;)V") private void setSelectedTab(ItemGroup group, CallbackInfo ci) { - this.owo$buttons.forEach(this::remove); - this.owo$buttons.clear(); + this.owoButtons.forEach(this::remove); + this.owoButtons.clear(); if (group instanceof OwoItemGroup owoGroup) { int tabRootY = this.y; @@ -151,7 +165,7 @@ private void setSelectedTab(ItemGroup group, CallbackInfo ci) { var tabButton = new ItemGroupButtonWidget(xOffset, yOffset, 32, tab, owo$createSelectAction(owoGroup, tabIdx)); if (owoGroup.isTabSelected(tabIdx)) tabButton.isSelected = true; - this.owo$buttons.add(tabButton); + this.owoButtons.add(tabButton); this.addDrawableChild(tabButton); } } @@ -168,7 +182,7 @@ private void setSelectedTab(ItemGroup group, CallbackInfo ci) { var tabButton = new ItemGroupButtonWidget(xOffset, yOffset, 0, buttonDefinition, __ -> buttonDefinition.action().run()); - this.owo$buttons.add(tabButton); + this.owoButtons.add(tabButton); this.addDrawableChild(tabButton); } } @@ -178,11 +192,11 @@ private void setSelectedTab(ItemGroup group, CallbackInfo ci) { private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { boolean anyButtonHovered = false; - for (var button : this.owo$buttons) { + for (var button : this.owoButtons) { if (button.trulyHovered()) { context.drawTooltip( this.textRenderer, - button.isTab() && ((OwoItemGroup)selectedTab).canSelectMultipleTabs() + button.isTab() && ((OwoItemGroup) selectedTab).canSelectMultipleTabs() ? List.of(button.getMessage(), Text.translatable("text.owo.itemGroup.select_hint")) : List.of(button.getMessage()), mouseX, @@ -192,12 +206,12 @@ private void render(DrawContext context, int mouseX, int mouseY, float delta, Ca } } - this.owo$cursorAdapter.applyStyle(anyButtonHovered ? CursorStyle.HAND : CursorStyle.NONE); + this.cursorAdapter.applyStyle(anyButtonHovered ? CursorStyle.HAND : CursorStyle.NONE); } @Inject(method = "removed", at = @At("HEAD")) private void disposeCursorAdapter(CallbackInfo ci) { - this.owo$cursorAdapter.dispose(); + this.cursorAdapter.dispose(); } @Override @@ -213,7 +227,7 @@ private void disposeCursorAdapter(CallbackInfo ci) { @Unique private Consumer owo$createSelectAction(OwoItemGroup group, int tabIdx) { return button -> { - var context = new ItemGroup.DisplayContext(this.owo$enabledFeatures, this.shouldShowOperatorTab(this.handler.player()), this.handler.player().getWorld().getRegistryManager()); + var context = new ItemGroup.DisplayContext(this.enabledFeatures, this.shouldShowOperatorTab(this.handler.player()), this.handler.player().getWorld().getRegistryManager()); if (Screen.hasShiftDown()) { group.toggleTab(tabIdx, context); } else { diff --git a/src/main/java/io/wispforest/owo/mixin/offline/AdvancementProgressAccessor.java b/src/main/java/io/wispforest/owo/mixin/offline/AdvancementProgressAccessor.java index 0e895b46..ff7d9401 100644 --- a/src/main/java/io/wispforest/owo/mixin/offline/AdvancementProgressAccessor.java +++ b/src/main/java/io/wispforest/owo/mixin/offline/AdvancementProgressAccessor.java @@ -1,6 +1,7 @@ package io.wispforest.owo.mixin.offline; import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.advancement.AdvancementRequirements; import net.minecraft.advancement.criterion.CriterionProgress; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -10,11 +11,8 @@ @Mixin(AdvancementProgress.class) public interface AdvancementProgressAccessor { @Accessor - Map getCriteriaProgresses(); + AdvancementRequirements getRequirements(); @Accessor - String[][] getRequirements(); - - @Accessor - void setRequirements(String[][] requirements); + void setRequirements(AdvancementRequirements requirements); } \ No newline at end of file diff --git a/src/main/java/io/wispforest/owo/mixin/offline/PlayerAdvancementTrackerMixin.java b/src/main/java/io/wispforest/owo/mixin/offline/PlayerAdvancementTrackerMixin.java index 38892587..badf7cf1 100644 --- a/src/main/java/io/wispforest/owo/mixin/offline/PlayerAdvancementTrackerMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/offline/PlayerAdvancementTrackerMixin.java @@ -18,9 +18,9 @@ public class PlayerAdvancementTrackerMixin { private ServerPlayerEntity owner; @SuppressWarnings("unchecked") - @ModifyArg(method = "save", at = @At(value = "INVOKE", target = "Lcom/google/gson/Gson;toJsonTree(Ljava/lang/Object;)Lcom/google/gson/JsonElement;", remap = false)) + @ModifyArg(method = "save", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/Codec;encodeStart(Lcom/mojang/serialization/DynamicOps;Ljava/lang/Object;)Lcom/mojang/serialization/DataResult;", remap = false), index = 1) private Object onAdvancementsSaved(Object map) { - DataSavedEvents.ADVANCEMENTS.invoker().onSaved(owner.getUuid(), (Map) map); + DataSavedEvents.ADVANCEMENTS.invoker().onSaved(owner.getUuid(), ((ProgressMapAccessor) map).getMap()); return map; } } diff --git a/src/main/java/io/wispforest/owo/mixin/offline/ProgressMapAccessor.java b/src/main/java/io/wispforest/owo/mixin/offline/ProgressMapAccessor.java new file mode 100644 index 00000000..41d92fee --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/offline/ProgressMapAccessor.java @@ -0,0 +1,14 @@ +package io.wispforest.owo.mixin.offline; + +import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(targets = "net/minecraft/advancement/PlayerAdvancementTracker$ProgressMap") +public interface ProgressMapAccessor { + @Accessor + Map getMap(); +} diff --git a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java b/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java index b017622d..7a696841 100644 --- a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java @@ -1,21 +1,27 @@ package io.wispforest.owo.mixin.recipe_remainders; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; +import com.mojang.serialization.JsonOps; import io.wispforest.owo.util.RecipeRemainderStorage; +import net.minecraft.inventory.Inventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Recipe; -import net.minecraft.recipe.RecipeManager; -import net.minecraft.recipe.ShapedRecipe; +import net.minecraft.recipe.*; import net.minecraft.util.Identifier; import net.minecraft.util.JsonHelper; +import net.minecraft.util.Util; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.world.World; 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.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.HashMap; +import java.util.Optional; @Mixin(RecipeManager.class) public abstract class RecipeManagerMixin { @@ -29,15 +35,30 @@ private static void deserializeRecipeSpecificRemainders(Identifier id, JsonObjec var item = JsonHelper.asItem(new JsonPrimitive(remainderEntry.getKey()), remainderEntry.getKey()); if (remainderEntry.getValue().isJsonObject()) { - var remainderStack = ShapedRecipe.outputFromJson(remainderEntry.getValue().getAsJsonObject()); - remainders.put(item, remainderStack); + var remainderStack = Util.getResult(RecipeCodecs.CRAFTING_RESULT.parse(JsonOps.INSTANCE, remainderEntry.getValue().getAsJsonObject()), JsonParseException::new); + remainders.put(item.value(), remainderStack); } else { var remainderItem = JsonHelper.asItem(remainderEntry.getValue(), "item"); - remainders.put(item, new ItemStack(remainderItem)); + remainders.put(item.value(), new ItemStack(remainderItem)); } } if (remainders.isEmpty()) return; RecipeRemainderStorage.store(id, remainders); } + + @Inject(method = "getRemainingStacks", at = @At(value = "RETURN", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) + private > void addRecipeSpecificRemainders(RecipeType type, I inventory, World world, CallbackInfoReturnable> cir, Optional> optional) { + if (optional.isEmpty() || !RecipeRemainderStorage.has(optional.get().id())) return; + + var remainders = cir.getReturnValue(); + var owoRemainders = RecipeRemainderStorage.get(optional.get().id()); + + for (int i = 0; i < remainders.size(); ++i) { + var item = inventory.getStack(i).getItem(); + if (!owoRemainders.containsKey(item)) continue; + + remainders.set(i, owoRemainders.get(item).copy()); + } + } } diff --git a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeMixin.java b/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeMixin.java deleted file mode 100644 index 39f8da50..00000000 --- a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.wispforest.owo.mixin.recipe_remainders; - -import io.wispforest.owo.util.RecipeRemainderStorage; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Recipe; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(Recipe.class) -public interface RecipeMixin { - - @Shadow - Identifier getId(); - - @Inject(method = "getRemainder", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD) - private void addRecipeSpecificRemainders(C inventory, CallbackInfoReturnable> cir, DefaultedList remainders) { - if (!RecipeRemainderStorage.has(this.getId())) return; - - var owoRemainders = RecipeRemainderStorage.get(this.getId()); - for (int i = 0; i < remainders.size(); ++i) { - var item = inventory.getStack(i).getItem(); - if (!owoRemainders.containsKey(item)) continue; - - remainders.set(i, owoRemainders.get(item).copy()); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/wispforest/owo/network/OwoHandshake.java b/src/main/java/io/wispforest/owo/network/OwoHandshake.java index e83fd9ff..79583d56 100644 --- a/src/main/java/io/wispforest/owo/network/OwoHandshake.java +++ b/src/main/java/io/wispforest/owo/network/OwoHandshake.java @@ -1,10 +1,8 @@ package io.wispforest.owo.network; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import io.wispforest.owo.Owo; -import io.wispforest.owo.mixin.ClientLoginNetworkHandlerAccessor; -import io.wispforest.owo.mixin.ServerLoginNetworkHandlerAccessor; +import io.wispforest.owo.mixin.ClientCommonNetworkHandlerAccessor; +import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor; import io.wispforest.owo.network.serialization.PacketBufSerializer; import io.wispforest.owo.ops.TextOps; import io.wispforest.owo.particles.systems.ParticleSystemController; @@ -12,19 +10,14 @@ import io.wispforest.owo.util.ServicesFrozenException; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; -import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.client.networking.v1.*; import net.fabricmc.fabric.api.networking.v1.*; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientLoginNetworkHandler; -import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.network.PacketByteBuf; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerLoginNetworkHandler; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -36,9 +29,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; import java.util.function.ToIntFunction; +@SuppressWarnings("UnstableApiUsage") @ApiStatus.Internal public final class OwoHandshake { @@ -60,7 +53,10 @@ private OwoHandshake() {} // Registration // ------------ - public static void enable() {} + public static void enable() { + if (OwoFreezer.isFrozen()) + throw new ServicesFrozenException("The oωo handshake may only be enabled during mod initialization"); + } public static void requireHandshake() { if (OwoFreezer.isFrozen()) @@ -70,25 +66,23 @@ public static void requireHandshake() { } static { - ServerLoginConnectionEvents.QUERY_START.register(OwoHandshake::queryStart); - ServerLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncServer); - - if (!ENABLED) { - ServerPlayNetworking.registerGlobalReceiver(OwoHandshake.OFF_CHANNEL_ID, (server, player, handler, buf, responseSender) -> {}); - } else { - ServerLifecycleEvents.SERVER_STARTED.register(server -> QUERY_RECEIVED = true); - } + ServerConfigurationConnectionEvents.CONFIGURE.register(OwoHandshake::configureStart); + ServerConfigurationNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncServer); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - ClientLoginNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncClient); - ClientPlayConnectionEvents.JOIN.register(OwoHandshake::handleJoinClient); + if (!ENABLED) { + ClientConfigurationNetworking.registerGlobalReceiver(OwoHandshake.OFF_CHANNEL_ID, (client, handler, buf, responseSender) -> {}); + } + + ClientConfigurationNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncClient); + ClientConfigurationConnectionEvents.READY.register(OwoHandshake::handleReadyClient); ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> QUERY_RECEIVED = false); - ClientLoginConnectionEvents.DISCONNECT.register((handler, client) -> QUERY_RECEIVED = false); + ClientConfigurationConnectionEvents.DISCONNECT.register((handler, client) -> QUERY_RECEIVED = false); } } - public static boolean isValid() { + public static boolean isValidClient() { return ENABLED && QUERY_RECEIVED; } @@ -96,23 +90,36 @@ public static boolean isValid() { // Packets // ------- - private static void queryStart(ServerLoginNetworkHandler serverLoginNetworkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer loginSynchronizer) { + private static void configureStart(ServerConfigurationNetworkHandler handler, MinecraftServer server) { if (!ENABLED) return; + if (ServerConfigurationNetworking.canSend(handler, OFF_CHANNEL_ID)) { + Owo.LOGGER.info("[Handshake] Handshake disabled by client, skipping"); + return; + } + + if (!ServerConfigurationNetworking.canSend(handler, CHANNEL_ID)) { + if (!HANDSHAKE_REQUIRED) return; + + handler.disconnect(TextOps.concat(PREFIX, Text.of("incompatible client"))); + Owo.LOGGER.info("[Handshake] Handshake failed, client doesn't understand channel packet"); + return; + } + var request = PacketByteBufs.create(); writeHashes(request, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); - sender.sendPacket(OwoHandshake.CHANNEL_ID, request); - Owo.LOGGER.info("[Handshake] Sending channel query"); + ServerConfigurationNetworking.send(handler, OwoHandshake.CHANNEL_ID, request); + Owo.LOGGER.info("[Handshake] Sending channel packet"); } @Environment(EnvType.CLIENT) - private static CompletableFuture syncClient(MinecraftClient client, ClientLoginNetworkHandler clientLoginNetworkHandler, PacketByteBuf buf, Consumer>> genericFutureListenerConsumer) { + private static void syncClient(MinecraftClient client, ClientConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender sender) { Owo.LOGGER.info("[Handshake] Sending client channels"); QUERY_RECEIVED = true; if (buf.readableBytes() > 0) { final var serverOptionalChannels = RESPONSE_SERIALIZER.deserializer().apply(buf); - ((OwoClientConnectionExtension) ((ClientLoginNetworkHandlerAccessor) clientLoginNetworkHandler).owo$getConnection()).owo$setChannelSet(filterOptionalServices(serverOptionalChannels, OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel)); + ((OwoClientConnectionExtension) ((ClientCommonNetworkHandlerAccessor) handler).getConnection()).owo$setChannelSet(filterOptionalServices(serverOptionalChannels, OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel)); } var response = PacketByteBufs.create(); @@ -120,18 +127,10 @@ private static CompletableFuture syncClient(MinecraftClient clien writeHashes(response, ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController); writeHashes(response, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); - return CompletableFuture.completedFuture(response); + sender.sendPacket(CHANNEL_ID, response); } - private static void syncServer(MinecraftServer server, ServerLoginNetworkHandler handler, boolean responded, PacketByteBuf buf, ServerLoginNetworking.LoginSynchronizer loginSynchronizer, PacketSender packetSender) { - if (!responded) { - if (!HANDSHAKE_REQUIRED) return; - - handler.disconnect(TextOps.concat(PREFIX, Text.of("incompatible client"))); - Owo.LOGGER.info("[Handshake] Handshake failed, client did not respond to channel query"); - return; - } - + private static void syncServer(MinecraftServer server, ServerConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { Owo.LOGGER.info("[Handshake] Receiving client channels"); final var clientChannels = RESPONSE_SERIALIZER.deserializer().apply(buf); @@ -148,17 +147,20 @@ private static void syncServer(MinecraftServer server, ServerLoginNetworkHandler if (buf.readableBytes() > 0) { final var clientOptionalChannels = RESPONSE_SERIALIZER.deserializer().apply(buf); - ((OwoClientConnectionExtension) ((ServerLoginNetworkHandlerAccessor) handler).owo$getConnection()).owo$setChannelSet(filterOptionalServices(clientOptionalChannels, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel)); + ((OwoClientConnectionExtension) ((ServerCommonNetworkHandlerAccessor) handler).owo$getConnection()).owo$setChannelSet(filterOptionalServices(clientOptionalChannels, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel)); } Owo.LOGGER.info("[Handshake] Handshake completed successfully"); } @Environment(EnvType.CLIENT) - private static void handleJoinClient(ClientPlayNetworkHandler handler, PacketSender packetSender, MinecraftClient client) { - if (QUERY_RECEIVED || ClientPlayNetworking.canSend(OFF_CHANNEL_ID) || !HANDSHAKE_REQUIRED || !ENABLED) return; + private static void handleReadyClient(ClientConfigurationNetworkHandler handler, MinecraftClient client) { + if (ClientConfigurationNetworking.canSend(CHANNEL_ID) || !HANDSHAKE_REQUIRED || !ENABLED) return; + client.execute(() -> { - handler.getConnection().disconnect(TextOps.concat(PREFIX, Text.of("incompatible server"))); + ((ClientCommonNetworkHandlerAccessor) handler) + .getConnection() + .disconnect(TextOps.concat(PREFIX, Text.of("incompatible server"))); }); } diff --git a/src/main/java/io/wispforest/owo/network/OwoNetChannel.java b/src/main/java/io/wispforest/owo/network/OwoNetChannel.java index b2a31fe8..ff2355b7 100644 --- a/src/main/java/io/wispforest/owo/network/OwoNetChannel.java +++ b/src/main/java/io/wispforest/owo/network/OwoNetChannel.java @@ -1,6 +1,6 @@ package io.wispforest.owo.network; -import io.wispforest.owo.mixin.ServerPlayNetworkHandlerAccessor; +import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor; import io.wispforest.owo.network.serialization.PacketBufSerializer; import io.wispforest.owo.network.serialization.RecordSerializer; import io.wispforest.owo.util.OwoFreezer; @@ -220,8 +220,8 @@ public boolean canSendToPlayer(ServerPlayerEntity player) { public boolean canSendToPlayer(ServerPlayNetworkHandler networkHandler) { if (required) return true; - return OwoHandshake.isValid() ? - getChannelSet(((ServerPlayNetworkHandlerAccessor) networkHandler).owo$getConnection()).contains(this.packetId) + return OwoHandshake.isValidClient() ? + getChannelSet(((ServerCommonNetworkHandlerAccessor) networkHandler).owo$getConnection()).contains(this.packetId) : ServerPlayNetworking.canSend(networkHandler, this.packetId); } @@ -229,7 +229,7 @@ public boolean canSendToPlayer(ServerPlayNetworkHandler networkHandler) { public boolean canSendToServer() { if (required) return true; - return OwoHandshake.isValid() ? + return OwoHandshake.isValidClient() ? getChannelSet(MinecraftClient.getInstance().getNetworkHandler().getConnection()).contains(packetId) : ClientPlayNetworking.canSend(this.packetId); } diff --git a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java index fa7616ae..e0b75a39 100644 --- a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java +++ b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java @@ -4,19 +4,25 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; +import com.mojang.serialization.Codec; import com.mojang.serialization.Dynamic; import com.mojang.serialization.JsonOps; import io.wispforest.owo.Owo; import io.wispforest.owo.mixin.offline.AdvancementProgressAccessor; +import net.minecraft.GameVersion; import net.minecraft.SharedConstants; import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementEntry; import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.advancement.PlayerAdvancementTracker; import net.minecraft.datafixer.DataFixTypes; import net.minecraft.datafixer.Schemas; import net.minecraft.util.Identifier; +import net.minecraft.util.Util; import net.minecraft.util.WorldSavePath; import org.jetbrains.annotations.Nullable; @@ -35,11 +41,15 @@ * @author BasiqueEvangelist */ public final class OfflineAdvancementLookup { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private OfflineAdvancementLookup() {} - private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(AdvancementProgress.class, new AdvancementProgress.Serializer()).registerTypeAdapter(Identifier.class, new Identifier.Serializer()).setPrettyPrinting().create(); - private static final TypeToken> JSON_TYPE = new TypeToken<>() {}; + public static final Codec> CODEC = DataFixTypes.ADVANCEMENTS.createDataFixingCodec( + Codec.unboundedMap(Identifier.CODEC, AdvancementProgress.CODEC), + Schemas.getFixer(), + 1343 + ); /** * Saves the given advancement state @@ -54,12 +64,10 @@ public static void put(UUID player, Map map) { try { Path advancementsPath = Owo.currentServer().getSavePath(WorldSavePath.ADVANCEMENTS); Path advancementPath = advancementsPath.resolve(player.toString() + ".json"); - JsonElement savedElement = GSON.toJsonTree(map); - savedElement.getAsJsonObject().addProperty("DataVersion", SharedConstants.getGameVersion().getSaveVersion().getId()); + JsonElement saved = Util.getResult(CODEC.encodeStart(JsonOps.INSTANCE, map), IllegalStateException::new); - try (OutputStream os = Files.newOutputStream(advancementPath); - OutputStreamWriter osWriter = new OutputStreamWriter(os, Charsets.UTF_8.newEncoder())) { - GSON.toJson(savedElement, osWriter); + try (BufferedWriter bw = Files.newBufferedWriter(advancementPath)) { + GSON.toJson(saved, bw); } } catch (IOException e) { @@ -88,27 +96,24 @@ public static void put(UUID player, Map map) { if (!Files.exists(advancementFile)) return null; - Dynamic dynamic; + Map parsedMap; + try (InputStream s = Files.newInputStream(advancementFile); InputStreamReader streamReader = new InputStreamReader(s); JsonReader reader = new JsonReader(streamReader)) { reader.setLenient(false); - dynamic = new Dynamic<>(JsonOps.INSTANCE, Streams.parse(reader)); - } - if (dynamic.get("DataVersion").asNumber().result().isEmpty()) { - dynamic = dynamic.set("DataVersion", dynamic.createInt(1343)); + JsonElement jsonElement = Streams.parse(reader); + parsedMap = Util.getResult(CODEC.parse(JsonOps.INSTANCE, jsonElement), JsonParseException::new); } - dynamic = DataFixTypes.ADVANCEMENTS.update(Schemas.getFixer(), dynamic, dynamic.get("DataVersion").asInt(0)); - dynamic = dynamic.remove("DataVersion"); - - Map parsedMap = GSON.getAdapter(JSON_TYPE).fromJsonTree(dynamic.getValue()); for (Map.Entry entry : parsedMap.entrySet()) { - if (((AdvancementProgressAccessor) entry.getValue()).getRequirements().length == 0) { - Advancement adv = Owo.currentServer().getAdvancementLoader().get(entry.getKey()); + var requirements = ((AdvancementProgressAccessor) entry.getValue()).getRequirements(); + + if (requirements.getLength() == 0) { + AdvancementEntry adv = Owo.currentServer().getAdvancementLoader().get(entry.getKey()); if (adv != null) { - ((AdvancementProgressAccessor) entry.getValue()).setRequirements(adv.getRequirements()); + ((AdvancementProgressAccessor) entry.getValue()).setRequirements(adv.value().requirements()); } } } diff --git a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementState.java b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementState.java index 1673c949..9a3614ec 100644 --- a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementState.java +++ b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementState.java @@ -1,6 +1,7 @@ package io.wispforest.owo.offline; import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementEntry; import net.minecraft.advancement.AdvancementProgress; import net.minecraft.util.Identifier; @@ -35,10 +36,10 @@ public Map advancementData() { * @param advancement The target advancement * @return The progress of the targeted advancement */ - public AdvancementProgress getOrAddProgress(Advancement advancement) { - return advancementData.computeIfAbsent(advancement.getId(), id -> { + public AdvancementProgress getOrAddProgress(AdvancementEntry advancement) { + return advancementData.computeIfAbsent(advancement.id(), id -> { AdvancementProgress progress = new AdvancementProgress(); - progress.init(advancement.getCriteria(), advancement.getRequirements()); + progress.init(advancement.value().requirements()); return progress; }); } @@ -49,7 +50,7 @@ public AdvancementProgress getOrAddProgress(Advancement advancement) { * * @param advancement The advancement to grant */ - public void grant(Advancement advancement) { + public void grant(AdvancementEntry advancement) { AdvancementProgress progress = getOrAddProgress(advancement); for (String criterion : progress.getUnobtainedCriteria()) { progress.obtain(criterion); @@ -62,7 +63,7 @@ public void grant(Advancement advancement) { * * @param advancement The advancement to revoke */ - public void revoke(Advancement advancement) { + public void revoke(AdvancementEntry advancement) { AdvancementProgress progress = getOrAddProgress(advancement); for (String criterion : progress.getObtainedCriteria()) { progress.reset(criterion); diff --git a/src/main/java/io/wispforest/owo/ui/base/BaseOwoHandledScreen.java b/src/main/java/io/wispforest/owo/ui/base/BaseOwoHandledScreen.java index 06772177..4edf3959 100644 --- a/src/main/java/io/wispforest/owo/ui/base/BaseOwoHandledScreen.java +++ b/src/main/java/io/wispforest/owo/ui/base/BaseOwoHandledScreen.java @@ -154,6 +154,9 @@ protected SlotComponent slotAsComponent(int index) { return this.uiAdapter.rootComponent.childById(expectedClass, id); } + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) {} + @Override public void render(DrawContext vanillaContext, int mouseX, int mouseY, float delta) { var context = OwoUIDrawContext.of(vanillaContext); diff --git a/src/main/java/io/wispforest/owo/ui/base/BaseOwoScreen.java b/src/main/java/io/wispforest/owo/ui/base/BaseOwoScreen.java index f690305f..8b339970 100644 --- a/src/main/java/io/wispforest/owo/ui/base/BaseOwoScreen.java +++ b/src/main/java/io/wispforest/owo/ui/base/BaseOwoScreen.java @@ -107,6 +107,9 @@ protected void init() { return this.uiAdapter.rootComponent.childById(expectedClass, id); } + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) {} + @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { if (!this.invalid) { diff --git a/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java b/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java index bf7f8415..57c48a1c 100644 --- a/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java @@ -1,7 +1,6 @@ package io.wispforest.owo.ui.component; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.brigadier.exceptions.CommandSyntaxException; import io.wispforest.owo.ui.base.BaseComponent; @@ -12,14 +11,16 @@ import io.wispforest.owo.ui.parsing.UIParsing; import io.wispforest.owo.util.pond.OwoEntityRenderDispatcherExtension; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.network.*; import net.minecraft.client.render.DiffuseLighting; import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.PlayerModelPart; +import net.minecraft.client.session.telemetry.TelemetrySender; +import net.minecraft.client.session.telemetry.WorldSession; +import net.minecraft.client.util.DefaultSkinHelper; +import net.minecraft.client.util.SkinTextures; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -29,7 +30,6 @@ import net.minecraft.network.ClientConnection; import net.minecraft.network.NetworkSide; import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; import net.minecraft.util.math.RotationAxis; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; @@ -242,40 +242,32 @@ public static EntityComponent parse(Element element) { public static class RenderablePlayerEntity extends ClientPlayerEntity { - protected Identifier skinTextureId = null; - protected String model = null; + protected SkinTextures skinTextures; protected RenderablePlayerEntity(GameProfile profile) { super(MinecraftClient.getInstance(), MinecraftClient.getInstance().world, new ClientPlayNetworkHandler(MinecraftClient.getInstance(), - null, new ClientConnection(NetworkSide.CLIENTBOUND), - null, - profile, - MinecraftClient.getInstance().getTelemetryManager().createWorldSession(false, Duration.ZERO, "tetris") - ), + new ClientConnectionState( + profile, new WorldSession(TelemetrySender.NOOP, false, Duration.ZERO, ""), + MinecraftClient.getInstance().world.getRegistryManager().toImmutable(), + MinecraftClient.getInstance().world.getEnabledFeatures(), + "Wisp Forest Enterprises", null, null + )), null, null, false, false ); - this.client.getSkinProvider().loadSkin(this.getGameProfile(), (type, identifier, texture) -> { - if (type != MinecraftProfileTexture.Type.SKIN) return; + this.skinTextures = DefaultSkinHelper.getTexture(profile); - this.skinTextureId = identifier; - this.model = texture.getMetadata("model"); - if (this.model == null) this.model = "default"; - - }, true); - } - - @Override - public boolean hasSkinTexture() { - return skinTextureId != null; + this.client.getSkinProvider().fetchSkinTextures(this.getGameProfile()).thenAccept(textures -> { + this.skinTextures = textures; + }); } @Override - public Identifier getSkinTexture() { - return this.skinTextureId != null ? this.skinTextureId : super.getSkinTexture(); + public SkinTextures getSkinTextures() { + return skinTextures; } @Override @@ -283,11 +275,6 @@ public boolean isPartVisible(PlayerModelPart modelPart) { return true; } - @Override - public String getModel() { - return this.model != null ? this.model : super.getModel(); - } - @Nullable @Override protected PlayerListEntry getPlayerListEntry() { diff --git a/src/main/java/io/wispforest/owo/ui/component/TextBoxComponent.java b/src/main/java/io/wispforest/owo/ui/component/TextBoxComponent.java index e3cf85d7..b5018c78 100644 --- a/src/main/java/io/wispforest/owo/ui/component/TextBoxComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/TextBoxComponent.java @@ -74,7 +74,7 @@ public EventSource onChanged() { public TextBoxComponent text(String text) { this.setText(text); - this.setCursorToStart(); + this.setCursorToStart(false); return this; } diff --git a/src/main/java/io/wispforest/owo/ui/component/VanillaWidgetComponent.java b/src/main/java/io/wispforest/owo/ui/component/VanillaWidgetComponent.java index 6ff8852d..856cbfae 100644 --- a/src/main/java/io/wispforest/owo/ui/component/VanillaWidgetComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/VanillaWidgetComponent.java @@ -16,7 +16,6 @@ public class VanillaWidgetComponent extends BaseComponent { private final ClickableWidget widget; private float time = 0f; - private @Nullable Runnable tickCallback = null; protected VanillaWidgetComponent(ClickableWidget widget) { this.widget = widget; @@ -24,25 +23,8 @@ protected VanillaWidgetComponent(ClickableWidget widget) { this.horizontalSizing.set(Sizing.fixed(this.widget.getWidth())); this.verticalSizing.set(Sizing.fixed(this.widget.getHeight())); - if (widget instanceof TextFieldWidget textField) { + if (widget instanceof TextFieldWidget) { this.margins(Insets.none()); - this.tickCallback = textField::tick; - } - - if (widget instanceof EditBoxWidget editBox) { - this.tickCallback = editBox::tick; - } - } - - @Override - public void update(float delta, int mouseX, int mouseY) { - super.update(delta, mouseX, mouseY); - if (this.tickCallback == null) return; - - this.time += delta; - while (this.time >= 1f) { - this.time -= 1f; - this.tickCallback.run(); } } @@ -161,7 +143,7 @@ public boolean onMouseUp(double mouseX, double mouseY, int button) { @Override public boolean onMouseScroll(double mouseX, double mouseY, double amount) { - return this.widget.mouseScrolled(this.x + mouseX, this.y + mouseY, amount) + return this.widget.mouseScrolled(this.x + mouseX, this.y + mouseY, 0, amount) | super.onMouseScroll(mouseX, mouseY, amount); } diff --git a/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java b/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java index c82d34ad..cdb15418 100644 --- a/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java +++ b/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java @@ -224,8 +224,8 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return this.rootComponent.onMouseScroll(mouseX, mouseY, amount); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + return this.rootComponent.onMouseScroll(mouseX, mouseY, verticalAmount); } @Override diff --git a/src/main/java/io/wispforest/owo/ui/hud/HudInspectorScreen.java b/src/main/java/io/wispforest/owo/ui/hud/HudInspectorScreen.java index 1ade071c..8d4015ea 100644 --- a/src/main/java/io/wispforest/owo/ui/hud/HudInspectorScreen.java +++ b/src/main/java/io/wispforest/owo/ui/hud/HudInspectorScreen.java @@ -17,7 +17,6 @@ public HudInspectorScreen() { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - this.renderBackground(context); super.render(context, mouseX, mouseY, delta); if (Hud.adapter == null) return; diff --git a/src/main/java/io/wispforest/owo/ui/layers/Layers.java b/src/main/java/io/wispforest/owo/ui/layers/Layers.java index 559483ab..c4b42f8f 100644 --- a/src/main/java/io/wispforest/owo/ui/layers/Layers.java +++ b/src/main/java/io/wispforest/owo/ui/layers/Layers.java @@ -118,7 +118,7 @@ public static Layer add(BiFu ScreenMouseEvents.allowMouseScroll(screeen).register((screen, mouseX, mouseY, horizontalAmount, verticalAmount) -> { boolean handled; for (var instance : getInstances(screen)) { - handled = instance.adapter.mouseScrolled(mouseX, mouseY, verticalAmount); + handled = instance.adapter.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); if (handled) return false; } diff --git a/src/main/java/io/wispforest/owo/ui/util/FocusHandler.java b/src/main/java/io/wispforest/owo/ui/util/FocusHandler.java index f3bfb119..1c02ac57 100644 --- a/src/main/java/io/wispforest/owo/ui/util/FocusHandler.java +++ b/src/main/java/io/wispforest/owo/ui/util/FocusHandler.java @@ -34,7 +34,7 @@ public Component.FocusSource lastFocusSource() { public void cycle(boolean forwards) { var allChildren = new ArrayList(); - this.root.collectChildren(allChildren); + this.root.collectDescendants(allChildren); allChildren.removeIf(component -> !component.canFocus(Component.FocusSource.KEYBOARD_CYCLE)); if (allChildren.isEmpty()) return; @@ -53,7 +53,7 @@ public void moveFocus(int keyCode) { if (this.focused == null) return; var allChildren = new ArrayList(); - this.root.collectChildren(allChildren); + this.root.collectDescendants(allChildren); allChildren.removeIf(component -> !component.canFocus(Component.FocusSource.KEYBOARD_CYCLE)); if (allChildren.isEmpty()) return; diff --git a/src/main/resources/owo.mixins.json b/src/main/resources/owo.mixins.json index 6d39c4ad..12d63b92 100644 --- a/src/main/resources/owo.mixins.json +++ b/src/main/resources/owo.mixins.json @@ -4,26 +4,26 @@ "package": "io.wispforest.owo.mixin", "compatibilityLevel": "JAVA_16", "mixins": [ + "ClientCommonNetworkHandlerAccessor", "ClientConnectionMixin", "Copenhagen", "ItemStackMixin", "NbtCompoundMixin", "ScreenHandlerInvoker", "ScreenHandlerMixin", - "ServerLoginNetworkHandlerAccessor", "ServerPlayerEntityMixin", "ServerPlayerInteractionManagerMixin", - "ServerPlayNetworkHandlerAccessor", + "ServerCommonNetworkHandlerAccessor", "SimpleRegistryMixin", "TagGroupLoaderMixin", "itemgroup.ItemGroupAccessor", "itemgroup.ItemMixin", "offline.AdvancementProgressAccessor", "offline.PlayerAdvancementTrackerMixin", + "offline.ProgressMapAccessor", "offline.WorldSaveHandlerMixin", "recipe_remainders.CraftingResultSlotMixin", "recipe_remainders.RecipeManagerMixin", - "recipe_remainders.RecipeMixin", "text.LanguageMixin", "text.TextSerializerMixin", "text.TranslatableTextContentMixin", diff --git a/src/testmod/java/io/wispforest/uwu/Uwu.java b/src/testmod/java/io/wispforest/uwu/Uwu.java index 42b1aae3..b0e6d3f1 100644 --- a/src/testmod/java/io/wispforest/uwu/Uwu.java +++ b/src/testmod/java/io/wispforest/uwu/Uwu.java @@ -89,7 +89,15 @@ public class Uwu implements ModInitializer { public static final OwoItemGroup SIX_TAB_GROUP = OwoItemGroup.builder(new Identifier("uwu", "six_tab_group"), () -> Icon.of(Items.POWDER_SNOW_BUCKET)) .tabStackHeight(3) - .customTexture(GROUP_TEXTURE) + .backgroundTexture(GROUP_TEXTURE) + .scrollerTextures(new OwoItemGroup.ScrollerTextures(new Identifier("uwu", "scroller"), new Identifier("uwu", "scroller_disabled"))) + .tabTextures(new OwoItemGroup.TabTextures( + new Identifier("uwu", "top_selected"), + new Identifier("uwu", "top_selected_first_column"), + new Identifier("uwu", "top_unselected"), + new Identifier("uwu", "bottom_selected"), + new Identifier("uwu", "bottom_selected_first_column"), + new Identifier("uwu", "bottom_unselected"))) .initializer(group -> { group.addTab(Icon.of(Items.DIAMOND), "tab_1", null, true); group.addTab(Icon.of(Items.EMERALD), "tab_2", null, false); diff --git a/src/testmod/java/io/wispforest/uwu/client/UwuClient.java b/src/testmod/java/io/wispforest/uwu/client/UwuClient.java index 8e252697..646c91b2 100644 --- a/src/testmod/java/io/wispforest/uwu/client/UwuClient.java +++ b/src/testmod/java/io/wispforest/uwu/client/UwuClient.java @@ -113,6 +113,8 @@ public void onInitializeClient() { }); Layers.add(Containers::verticalFlow, instance -> { + if (MinecraftClient.getInstance().world == null) return; + instance.adapter.rootComponent.child( Containers.horizontalFlow(Sizing.content(), Sizing.content()) .child(Components.entity(Sizing.fixed(20), EntityType.ALLAY, null).>configure(component -> { diff --git a/src/testmod/resources/assets/uwu/textures/gui/group.png b/src/testmod/resources/assets/uwu/textures/gui/group.png index e71054f8..d079b245 100644 Binary files a/src/testmod/resources/assets/uwu/textures/gui/group.png and b/src/testmod/resources/assets/uwu/textures/gui/group.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected.png new file mode 100644 index 00000000..cc1c4bd5 Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected_first_column.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected_first_column.png new file mode 100644 index 00000000..e8b54db1 Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_selected_first_column.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_unselected.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_unselected.png new file mode 100644 index 00000000..a15b1e5c Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/bottom_unselected.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller.png new file mode 100644 index 00000000..57a02f7b Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller_disabled.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller_disabled.png new file mode 100644 index 00000000..ae24e31b Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/scroller_disabled.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected.png new file mode 100644 index 00000000..ce80bddd Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected_first_column.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected_first_column.png new file mode 100644 index 00000000..f2bfc8d2 Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_selected_first_column.png differ diff --git a/src/testmod/resources/assets/uwu/textures/gui/sprites/top_unselected.png b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_unselected.png new file mode 100644 index 00000000..62e9c828 Binary files /dev/null and b/src/testmod/resources/assets/uwu/textures/gui/sprites/top_unselected.png differ