diff --git a/src/generated/resources/assets/ltminigames/lang/en_ud.json b/src/generated/resources/assets/ltminigames/lang/en_ud.json index b0503b5f4..14f4e5167 100644 --- a/src/generated/resources/assets/ltminigames/lang/en_ud.json +++ b/src/generated/resources/assets/ltminigames/lang/en_ud.json @@ -169,6 +169,8 @@ "ltminigames.minigame.chaos_block_party": "ʎʇɹɐԀ ʞɔoןᗺ soɐɥƆ", "ltminigames.minigame.conservation_exploration": "uoıʇɐɹoןdxƎ uoıʇɐʌɹǝsuoƆ", "ltminigames.minigame.crafting_bee.dont_cheat": "¡ʇɐǝɥɔ ʇ,uoᗡ", + "ltminigames.minigame.crafting_bee.hint": "sʇuǝıpǝɹbuı ɟo ɹǝqɯnu ɯopuɐɹ ɐ ɟo uoıʇısod ǝɥʇ buıʎɐןdsıp 'ʇuıɥ ɐ ʍoɥs oʇ ʞɔıןƆ", + "ltminigames.minigame.crafting_bee.hints_left": "ʇɟǝן sʇuıɥ %s ǝʌɐɥ noʎ", "ltminigames.minigame.crafting_bee.team_has_completed_recipes": "sǝdıɔǝɹ %s ɟo ʇno %s pǝʇǝןdɯoɔ sɐɥ %s ɯɐǝ⟘", "ltminigames.minigame.donation.acid_rain": "uıɐᴚ pıɔⱯ", "ltminigames.minigame.donation.acid_rain.description": "¡ǝʇnuıɯ Ɩ ɹoɟ spɐǝɥ ,sɹǝʎɐןd ǝɥʇ uo uʍop pıɔɐ uıɐᴚ", diff --git a/src/generated/resources/assets/ltminigames/lang/en_us.json b/src/generated/resources/assets/ltminigames/lang/en_us.json index b1f11295c..a8b76c3ef 100644 --- a/src/generated/resources/assets/ltminigames/lang/en_us.json +++ b/src/generated/resources/assets/ltminigames/lang/en_us.json @@ -169,6 +169,8 @@ "ltminigames.minigame.chaos_block_party": "Chaos Block Party", "ltminigames.minigame.conservation_exploration": "Conservation Exploration", "ltminigames.minigame.crafting_bee.dont_cheat": "Don't cheat!", + "ltminigames.minigame.crafting_bee.hint": "Click to show a hint, displaying the position of a random number of ingredients", + "ltminigames.minigame.crafting_bee.hints_left": "You have %s hints left", "ltminigames.minigame.crafting_bee.team_has_completed_recipes": "Team %s has completed %s out of %s recipes", "ltminigames.minigame.donation.acid_rain": "Acid Rain", "ltminigames.minigame.donation.acid_rain.description": "Rain acid down on the players' heads for 1 minute!", diff --git a/src/main/java/com/lovetropics/minigames/client/game/handler/GameCraftingBeeHandler.java b/src/main/java/com/lovetropics/minigames/client/game/handler/GameCraftingBeeHandler.java index 5efcd8659..0bc3d57ca 100644 --- a/src/main/java/com/lovetropics/minigames/client/game/handler/GameCraftingBeeHandler.java +++ b/src/main/java/com/lovetropics/minigames/client/game/handler/GameCraftingBeeHandler.java @@ -3,6 +3,7 @@ import com.lovetropics.minigames.LoveTropics; import com.lovetropics.minigames.client.game.ClientGameStateManager; import com.lovetropics.minigames.common.content.crafting_bee.CraftingBeeTexts; +import com.lovetropics.minigames.common.content.crafting_bee.SelectedRecipe; import com.lovetropics.minigames.common.core.game.client_state.GameClientStateTypes; import com.lovetropics.minigames.common.core.game.client_state.instance.CraftingBeeCrafts; import com.mojang.blaze3d.platform.GlStateManager; @@ -14,38 +15,98 @@ import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.CraftingScreen; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.NonNullList; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RegisterClientTooltipComponentFactoriesEvent; import net.neoforged.neoforge.client.event.ScreenEvent; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Random; +import java.util.UUID; +import java.util.function.Predicate; @EventBusSubscriber(modid = LoveTropics.ID, value = Dist.CLIENT) public class GameCraftingBeeHandler { - // TODO - hints - private static int hintsRemaining = 3; + private static int hintsRemaining; + private static UUID lastKnownGame; + private static Map hintGrids; + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("ltminigames", "textures/gui/minigames/crafting_bee/items_bar.png"); + private static final ResourceLocation GRID_TEXTURE = ResourceLocation.fromNamespaceAndPath("ltminigames", "textures/gui/minigames/crafting_bee/crafting_grid.png"); + + @EventBusSubscriber(modid = LoveTropics.ID, value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD) + public static class ModSubscriber { + @SubscribeEvent + static void onRegisterTooltips(final RegisterClientTooltipComponentFactoriesEvent event) { + event.register(RecipeHint.class, recipeHint -> new ClientTooltipComponent() { + @Override + public int getHeight() { + return 58; + } + + @Override + public int getWidth(Font font) { + return 54; + } + + @Override + public void renderImage(Font font, int x, int y, GuiGraphics guiGraphics) { + guiGraphics.blit(GRID_TEXTURE, x, y, 0, 0, 54, 54, 54, 54); + for (int i = 0; i < recipeHint.grid().size(); i++) { + var ingredient = recipeHint.grid.get(i); + if (ingredient.isEmpty()) continue; + + var size = recipeHint.grid.size() == 4 ? 2 : 3; + + guiGraphics.renderFakeItem( + resolveIngredient(ingredient), + x + 1 + 18 * (i % size), + y + 1 + 18 * (i / size) + ); + } + } + }); + } + } @SubscribeEvent static void onGuiInit(ScreenEvent.Init.Post event) { if (getState() == null || !(event.getScreen() instanceof CraftingScreen screen)) return; + var state = getState(); + if (!Objects.equals(state.gameId(), lastKnownGame)) { + lastKnownGame = state.gameId(); + hintsRemaining = state.allowedHints(); + hintGrids = new HashMap<>(); + } + event.addListener(new AbstractWidget(screen.getGuiLeft() + 22, screen.getGuiTop() - 21, 132, 21, Component.empty()) { @Override protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { @@ -57,16 +118,66 @@ protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, flo renderItem(guiGraphics, craft.output(), x, this.getY() + 4, 0, 0, 1f, 1f, 1f, craft.done() ? .1f : 1f); if (mouseX >= x && mouseX <= x + 16 && mouseY >= getY() + 4 && mouseY <= getY() + 20) { + var hint = hintGrids.get(craft.recipeId()); + var tooltipLines = new ArrayList<>(Screen.getTooltipFromItem(Minecraft.getInstance(), craft.output())); if (craft.done()) { tooltipLines.set(0, tooltipLines.get(0).copy().withStyle(ChatFormatting.GREEN)); - } else { + } else if (hint == null || hint.expectedIngredientCount() != hint.grid().stream().filter(Predicate.not(Ingredient::isEmpty)).count()) { tooltipLines.add(CraftingBeeTexts.HINT); tooltipLines.add(CraftingBeeTexts.HINTS_LEFT.apply(Component.literal(String.valueOf(hintsRemaining)).withStyle(ChatFormatting.AQUA))); } - guiGraphics.renderTooltip(Minecraft.getInstance().font, tooltipLines, craft.output().getTooltipImage(), mouseX, mouseY); + guiGraphics.renderTooltip(Minecraft.getInstance().font, tooltipLines, Optional.ofNullable(hint).filter($ -> !craft.done()), mouseX, mouseY); + } + } + } + + @Override + public void onClick(double mouseX, double mouseY, int button) { + if (hintsRemaining <= 0) return; + + var crafts = getState().crafts(); + + if (mouseY < getY() + 4 || mouseY > getY() + 4 + 16) return; + if (mouseX < getX() + 4 || mouseX > getX() + 4 + (18 * crafts.size() - 1)) return; + var index = (int)(mouseX - getX() - 4) / 18; + + var craft = crafts.get(index); + if (craft.done()) return; + + var recipe = new SelectedRecipe(craft.recipeId(), Minecraft.getInstance().player.connection.getRecipeManager()); + var ingredients = recipe.decompose(); + + var grid = hintGrids.computeIfAbsent(craft.recipeId(), k -> new RecipeHint( + NonNullList.withSize( + recipe.recipe().map(shaped -> shaped.getWidth() * shaped.getHeight(), shapeless -> shapeless.getIngredients().size() > 3 ? 9 : shapeless.getIngredients().size()), + Ingredient.EMPTY), + (int)ingredients.stream().filter(Predicate.not(Ingredient::isEmpty)).count() + )); + + int filledGridAmount = (int) grid.grid().stream().filter(Predicate.not(Ingredient::isEmpty)).count(); + if (grid.expectedIngredientCount() == filledGridAmount) return; + + record PositionedIngredient(Ingredient ingredient, int position) {} + + List ingredientsToPick = new ArrayList<>(); + for (int i = 0; i < ingredients.size(); i++) { + var ingr = ingredients.get(i); + if (!ingr.isEmpty() && grid.grid().get(i).isEmpty()) { + ingredientsToPick.add(new PositionedIngredient(ingr, i)); } } + + Collections.shuffle(ingredientsToPick); + // Make sure that we never show the full recipe in just one hint + var ingredientsToShow = new Random().nextInt(filledGridAmount == 0 ? Math.max(1, ingredientsToPick.size() - 1) : ingredientsToPick.size()); + + for (int i = 0; i <= ingredientsToShow; i++) { + var ingredient = ingredientsToPick.get(i); + grid.grid().set(ingredient.position(), ingredient.ingredient()); + } + + hintsRemaining--; } @Override @@ -81,6 +192,19 @@ private static CraftingBeeCrafts getState() { return ClientGameStateManager.getOrNull(GameClientStateTypes.CRAFTING_BEE_CRAFTS); } + private static ItemStack resolveIngredient(Ingredient ingredient) { + if (ingredient.isEmpty()) { + return ItemStack.EMPTY; + } + for (ItemStack item : ingredient.getItems()) { + // Prioritize vanilla items + if (item.getItem().builtInRegistryHolder().key().location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) { + return item; + } + } + return ingredient.getItems()[0]; + } + public static void reset() { } @@ -186,4 +310,10 @@ public TintedVertexConsumer(VertexConsumer wrapped, float red, float green, floa this.alpha = alpha; } } + + public record RecipeHint( + NonNullList grid, + int expectedIngredientCount + ) implements TooltipComponent {} + } diff --git a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeBehavior.java b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeBehavior.java index a2fff9e75..1dce916cf 100644 --- a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeBehavior.java +++ b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeBehavior.java @@ -20,11 +20,11 @@ import com.lovetropics.minigames.common.core.game.state.team.GameTeam; import com.lovetropics.minigames.common.core.game.state.team.GameTeamKey; import com.lovetropics.minigames.common.core.game.state.team.TeamState; +import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.ChatFormatting; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.TickTask; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; @@ -33,28 +33,33 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.Stream; public class CraftingBeeBehavior implements IGameBehavior { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(in -> in.group( RecipeSelector.CODEC.codec().listOf().fieldOf("selectors").forGetter(c -> c.selectors), - IngredientDecomposer.CODEC.codec().listOf().fieldOf("decomposers").forGetter(c -> c.decomposers) + IngredientDecomposer.CODEC.codec().listOf().fieldOf("decomposers").forGetter(c -> c.decomposers), + Codec.INT.optionalFieldOf("hints_per_player", 3).forGetter(c -> c.allowedHints) ).apply(in, CraftingBeeBehavior::new)); private final List selectors; private final List decomposers; + private final int allowedHints; private TeamState teams; private IGamePhase game; private ListMultimap tasks; - public CraftingBeeBehavior(List selectors, List decomposers) { + public CraftingBeeBehavior(List selectors, List decomposers, int allowedHints) { this.selectors = selectors; this.decomposers = decomposers; + this.allowedHints = allowedHints; } @Override @@ -91,7 +96,8 @@ private void distributeIngredients(Collection tasks, PlayerSet pla for (CraftingTask task : tasks) { var ingredients = task.recipe.decompose(); - var items = ingredients.stream().flatMap(this::singleDecomposition).toList(); + var items = ingredients.stream().flatMap(this::singleDecomposition).collect(Collectors.toCollection(ArrayList::new)); + Collections.shuffle(items); // Evenly distribute the items between the players int p = 0; @@ -104,13 +110,14 @@ private void distributeIngredients(Collection tasks, PlayerSet pla } private Stream singleDecomposition(Ingredient ingredient) { + if (ingredient.isEmpty()) return Stream.empty(); + for (IngredientDecomposer decomposer : decomposers) { var decomposed = decomposer.decompose(ingredient); if (decomposed != null) { return decomposed.stream().flatMap(this::singleDecomposition); } } - if (ingredient.getItems().length == 0) return Stream.empty(); // We have reduced the ingredient to its most basic form, so now we just pick the first item of the ingredient for (ItemStack item : ingredient.getItems()) { @@ -128,7 +135,7 @@ private void onCraft(Player player, ItemStack crafted, Container container) { var teamTasks = tasks.get(team); var task = teamTasks.stream().filter(c -> ItemStack.isSameItemSameComponents(crafted, c.output)).findFirst().orElse(null); - if (task == null) return; + if (task == null || task.done) return; task.done = true; @@ -157,7 +164,8 @@ private void sync(GameTeamKey team) { private void sync(Player player) { if (player instanceof ServerPlayer sp) { - GameClientState.sendToPlayer(new CraftingBeeCrafts(tasks.get(teams.getTeamForPlayer(player)).stream().map(CraftingTask::toCraft).toList()), sp); + GameClientState.sendToPlayer(new CraftingBeeCrafts(tasks.get(teams.getTeamForPlayer(player)).stream().map(CraftingTask::toCraft).toList(), + game.gameUuid(), allowedHints), sp); } } @@ -168,10 +176,10 @@ public Supplier> behaviorType() { private static class CraftingTask { private final ItemStack output; - private final RecipeSelector.SelectedRecipe recipe; + private final SelectedRecipe recipe; private boolean done; - private CraftingTask(ItemStack output, RecipeSelector.SelectedRecipe recipe) { + private CraftingTask(ItemStack output, SelectedRecipe recipe) { this.output = output; this.recipe = recipe; } diff --git a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeTexts.java b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeTexts.java index a571afcc6..9c4fd32cc 100644 --- a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeTexts.java +++ b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/CraftingBeeTexts.java @@ -1,7 +1,6 @@ package com.lovetropics.minigames.common.content.crafting_bee; import com.lovetropics.minigames.LoveTropics; -import com.lovetropics.minigames.common.content.MinigameTexts; import com.lovetropics.minigames.common.core.game.util.TranslationCollector; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; @@ -11,6 +10,6 @@ public final class CraftingBeeTexts { public static final TranslationCollector.Fun3 TEAM_HAS_COMPLETED_RECIPES = KEYS.add3("team_has_completed_recipes", "Team %s has completed %s out of %s recipes"); public static final Component DONT_CHEAT = KEYS.add("dont_cheat", "Don't cheat!").withStyle(ChatFormatting.RED); - public static final Component HINT = MinigameTexts.KEYS.add("hint", "Click to show a hint, displaying the position of a random number of ingredients"); - public static final TranslationCollector.Fun1 HINTS_LEFT = MinigameTexts.KEYS.add1("hints_left", "You have %s hints left"); + public static final Component HINT = KEYS.add("hint", "Click to show a hint, displaying the position of a random number of ingredients"); + public static final TranslationCollector.Fun1 HINTS_LEFT = KEYS.add1("hints_left", "You have %s hints left"); } diff --git a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/RecipeSelector.java b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/RecipeSelector.java index a72dfa02e..64842c7c5 100644 --- a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/RecipeSelector.java +++ b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/RecipeSelector.java @@ -2,18 +2,11 @@ import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; -import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import net.minecraft.Util; -import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.item.crafting.ShapedRecipe; -import net.minecraft.world.item.crafting.ShapelessRecipe; import java.util.List; @@ -25,20 +18,6 @@ public interface RecipeSelector { MapCodec getType(); - record SelectedRecipe(ResourceLocation id, Either recipe) { - public SelectedRecipe(RecipeHolder holder) { - this(holder.id(), holder.value() instanceof ShapedRecipe sr ? Either.left(sr) : Either.right((ShapelessRecipe) holder.value())); - } - - public ItemStack getResult(RegistryAccess access) { - return recipe.map(rp -> rp.getResultItem(access), rp -> rp.getResultItem(access)); - } - - public List decompose() { - return recipe.map(ShapedRecipe::getIngredients, ShapelessRecipe::getIngredients); - } - } - record FromList(List recipes) implements RecipeSelector { public static final MapCodec CODEC = ResourceLocation.CODEC.listOf().fieldOf("recipes") .xmap(FromList::new, FromList::recipes); diff --git a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/SelectedRecipe.java b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/SelectedRecipe.java new file mode 100644 index 000000000..2c65fa867 --- /dev/null +++ b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/SelectedRecipe.java @@ -0,0 +1,31 @@ +package com.lovetropics.minigames.common.content.crafting_bee; + +import com.mojang.datafixers.util.Either; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; + +import java.util.List; + +public record SelectedRecipe(ResourceLocation id, Either recipe) { + public SelectedRecipe(RecipeHolder holder) { + this(holder.id(), holder.value() instanceof ShapedRecipe sr ? Either.left(sr) : Either.right((ShapelessRecipe) holder.value())); + } + + public SelectedRecipe(ResourceLocation id, RecipeManager manager) { + this(manager.byKey(id).orElseThrow()); + } + + public ItemStack getResult(RegistryAccess access) { + return recipe.map(rp -> rp.getResultItem(access), rp -> rp.getResultItem(access)); + } + + public List decompose() { + return recipe.map(ShapedRecipe::getIngredients, ShapelessRecipe::getIngredients); + } +} diff --git a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/ingredient/FromRecipeDecomposer.java b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/ingredient/FromRecipeDecomposer.java index 3f7f79890..b52b889a7 100644 --- a/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/ingredient/FromRecipeDecomposer.java +++ b/src/main/java/com/lovetropics/minigames/common/content/crafting_bee/ingredient/FromRecipeDecomposer.java @@ -1,6 +1,6 @@ package com.lovetropics.minigames.common.content.crafting_bee.ingredient; -import com.lovetropics.minigames.common.content.crafting_bee.RecipeSelector; +import com.lovetropics.minigames.common.content.crafting_bee.SelectedRecipe; import com.mojang.serialization.MapCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -38,7 +38,7 @@ public void prepareCache(ServerLevel level) { cache.clear(); for (ResourceLocation recipe : recipes) { - level.getServer().getRecipeManager().byKey(recipe).map(RecipeSelector.SelectedRecipe::new) + level.getServer().getRecipeManager().byKey(recipe).map(SelectedRecipe::new) .ifPresent(r -> cache.put( r.getResult(level.registryAccess()).getItem(), r.decompose() diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/CraftingBeeCrafts.java b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/CraftingBeeCrafts.java index fd1857474..4ad5f7622 100644 --- a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/CraftingBeeCrafts.java +++ b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/CraftingBeeCrafts.java @@ -6,14 +6,20 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.UUIDUtil; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ExtraCodecs; import net.minecraft.world.item.ItemStack; import java.util.List; +import java.util.UUID; -public record CraftingBeeCrafts(List crafts) implements GameClientState { - public static final MapCodec CODEC = Craft.CODEC.listOf() - .fieldOf("crafts").xmap(CraftingBeeCrafts::new, CraftingBeeCrafts::crafts); +public record CraftingBeeCrafts(List crafts, UUID gameId, int allowedHints) implements GameClientState { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(in -> in.group( + Craft.CODEC.listOf().fieldOf("crafts").forGetter(CraftingBeeCrafts::crafts), + UUIDUtil.CODEC.fieldOf("gameId").forGetter(CraftingBeeCrafts::gameId), + Codec.INT.fieldOf("allowedHints").forGetter(CraftingBeeCrafts::allowedHints) + ).apply(in, CraftingBeeCrafts::new)); @Override public GameClientStateType getType() { diff --git a/src/main/java/com/lovetropics/minigames/mixin/client/HiddenRecipeBookMixin.java b/src/main/java/com/lovetropics/minigames/mixin/client/HiddenRecipeBookMixin.java index e56a694ac..68942e8fc 100644 --- a/src/main/java/com/lovetropics/minigames/mixin/client/HiddenRecipeBookMixin.java +++ b/src/main/java/com/lovetropics/minigames/mixin/client/HiddenRecipeBookMixin.java @@ -29,7 +29,7 @@ public class HiddenRecipeBookMixin { @Inject(method = "init", at = @At("HEAD")) private void hideBookIfOpen(CallbackInfo ci) { - if (ClientGameStateManager.getOrNull(GameClientStateTypes.HIDE_RECIPE_BOOK) != null && recipeBookComponent.isVisible()) { + if (ClientGameStateManager.getOrNull(GameClientStateTypes.HIDE_RECIPE_BOOK) != null) { Minecraft.getInstance().player.getRecipeBook().setBookSetting(RecipeBookType.CRAFTING, false, false); } } diff --git a/src/main/resources/assets/ltminigames/textures/gui/minigames/crafting_bee/crafting_grid.png b/src/main/resources/assets/ltminigames/textures/gui/minigames/crafting_bee/crafting_grid.png new file mode 100644 index 000000000..6bcd16977 Binary files /dev/null and b/src/main/resources/assets/ltminigames/textures/gui/minigames/crafting_bee/crafting_grid.png differ