Skip to content

Commit

Permalink
结构工具按钮,导出功能实现
Browse files Browse the repository at this point in the history
  • Loading branch information
DancingSnow0517 committed Sep 26, 2024
1 parent 5a35e7d commit 1a30b97
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 122 deletions.
9 changes: 9 additions & 0 deletions src/generated/resources/assets/anvilcraft/lang/en_ud.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,13 @@
"itemGroup.anvilcraft.functional_block": "ʞɔoןᗺ ןɐuoıʇɔunℲ :ʇɟɐɹƆןıʌuⱯ",
"itemGroup.anvilcraft.ingredients": "sʇuǝıpǝɹbuI :ʇɟɐɹƆןıʌuⱯ",
"itemGroup.anvilcraft.tools": "sǝıʇıןıʇ∩ :ʇɟɐɹƆןıʌuⱯ",
"message.anvilcraft.code_gen_check": "˙sɯǝʇı sɐɥ ʇoןs ʇndʇno ǝɥʇ ɟı puɐ ǝqnɔ ɐ sı ɐǝɹɐ pǝʇɔǝןǝs ǝɥʇ ɟı ʞɔǝɥɔ ǝsɐǝןԀ",
"message.anvilcraft.code_gen_filed": "pǝןıɐɟ uoıʇɐɹǝuǝb ǝpoƆ",
"message.anvilcraft.copied_to_clipboard": "pɹɐoqdıןɔ oʇ pǝıdoƆ",
"message.anvilcraft.file_save_failed": "%s '%s ǝןıɟ buıʌɐs ǝןıɥʍ pǝɹɹnɔɔo ǝnssı uⱯ",
"message.anvilcraft.file_saved": "%s oʇ pǝʌɐs ǝןıℲ",
"message.anvilcraft.need_patchouli_installed": "pǝןןɐʇsuı ǝq oʇ spǝǝu ıןnoɥɔʇɐԀ",
"message.anvilcraft.no_file_selected": "pǝʇɔǝןǝs ɥʇɐd ǝןıɟ oN",
"modmenu.nameTranslation.anvilcraft": "ʇɟɐɹƆןıʌuⱯ",
"pack.anvilcraft.builtin_pack": "ʞɔɐԀǝɔɹnosǝᴚ uıʇןınᗺ ʇɟɐɹƆןıʌuⱯ",
"pack.anvilcraft.transparent_cauldron.description": "uoɹpןnɐƆ ʇuǝɹɐdsuɐɹ⟘",
Expand Down Expand Up @@ -393,6 +399,9 @@
"screen.anvilcraft.smithing_template.royal_steel_upgrade_smithing_template.base_slot_description": " ʇnԀ",
"screen.anvilcraft.structure_tool.count": "%d :ʇunoƆ",
"screen.anvilcraft.structure_tool.size": ":ǝzıS",
"screen.anvilcraft.structure_tool.to_data_gen": "uǝ⅁ ɐʇɐᗡ o⟘",
"screen.anvilcraft.structure_tool.to_json": "NOSſ o⟘",
"screen.anvilcraft.structure_tool.to_kubejs": "Sſǝqnʞ o⟘",
"text.autoconfig.anvilcraft.option.anvilEfficiency": "ʎɔuǝıɔıɟɟƎ ןıʌuⱯ",
"text.autoconfig.anvilcraft.option.anvilEfficiency.@Tooltip": "ǝɯıʇ ǝɯɐs ǝɥʇ ʇɐ ןıʌuɐ ǝɥʇ ʎq pǝssǝɔoɹd sɯǝʇı ɟo ɹǝqɯnu ɯnɯıxɐW",
"text.autoconfig.anvilcraft.option.autoCrafterCooldown": "uʍopןooƆ ɹǝʇɟɐɹƆ oʇnⱯ",
Expand Down
9 changes: 9 additions & 0 deletions src/generated/resources/assets/anvilcraft/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,13 @@
"itemGroup.anvilcraft.functional_block": "AnvilCraft: Functional Block",
"itemGroup.anvilcraft.ingredients": "AnvilCraft: Ingredients",
"itemGroup.anvilcraft.tools": "AnvilCraft: Utilities",
"message.anvilcraft.code_gen_check": "Please check if the selected area is a cube and if the output slot has items.",
"message.anvilcraft.code_gen_filed": "Code generation failed",
"message.anvilcraft.copied_to_clipboard": "Copied to clipboard",
"message.anvilcraft.file_save_failed": "An issue occurred while saving file %s, %s",
"message.anvilcraft.file_saved": "File saved to %s",
"message.anvilcraft.need_patchouli_installed": "Patchouli needs to be installed",
"message.anvilcraft.no_file_selected": "No file path selected",
"modmenu.nameTranslation.anvilcraft": "AnvilCraft",
"pack.anvilcraft.builtin_pack": "AnvilCraft Builtin ResourcePack",
"pack.anvilcraft.transparent_cauldron.description": "Transparent Cauldron",
Expand Down Expand Up @@ -393,6 +399,9 @@
"screen.anvilcraft.smithing_template.royal_steel_upgrade_smithing_template.base_slot_description": "Put ",
"screen.anvilcraft.structure_tool.count": "Count: %d",
"screen.anvilcraft.structure_tool.size": "Size:",
"screen.anvilcraft.structure_tool.to_data_gen": "To Data Gen",
"screen.anvilcraft.structure_tool.to_json": "To JSON",
"screen.anvilcraft.structure_tool.to_kubejs": "To KubeJS",
"text.autoconfig.anvilcraft.option.anvilEfficiency": "Anvil Efficiency",
"text.autoconfig.anvilcraft.option.anvilEfficiency.@Tooltip": "Maximum number of items processed by the anvil at the same time",
"text.autoconfig.anvilcraft.option.autoCrafterCooldown": "Auto Crafter Cooldown",
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/dev/dubhe/anvilcraft/AnvilCraft.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.neoforged.neoforge.network.registration.PayloadRegistrar;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.tterrag.registrate.Registrate;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.serializer.JanksonConfigSerializer;
Expand All @@ -49,6 +51,8 @@ public class AnvilCraft {
public static final String MOD_ID = "anvilcraft";
public static final String MOD_NAME = "AnvilCraft";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME);
public static final Gson GSON =
new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
public static IEventBus EVENT_BUS;
public static AnvilCraftConfig config = AutoConfig.register(AnvilCraftConfig.class, JanksonConfigSerializer::new)
.getConfig();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,183 @@
import dev.dubhe.anvilcraft.AnvilCraft;
import dev.dubhe.anvilcraft.inventory.StructureToolMenu;
import dev.dubhe.anvilcraft.item.StructureToolItem;
import dev.dubhe.anvilcraft.recipe.multiblock.BlockPattern;
import dev.dubhe.anvilcraft.recipe.multiblock.BlockPredicateWithState;
import dev.dubhe.anvilcraft.recipe.multiblock.MultiblockRecipe;

import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.gui.components.WidgetSprites;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;

import com.google.gson.JsonElement;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.serialization.JsonOps;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.tinyfd.TinyFileDialogs;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class StructureToolScreen extends AbstractContainerScreen<StructureToolMenu> {
private final ResourceLocation CONTAINER_LOCATION =
AnvilCraft.of("textures/gui/container/structure_tool/background.png");

private static final WidgetSprites SPRITES = new WidgetSprites(
AnvilCraft.of("widget/structure_tool/button"), AnvilCraft.of("widget/structure_tool/button_highlighted"));

private static char currentSymbol;

private ImageButton dataGenButton;
private ImageButton kubejsButton;
private ImageButton jsonButton;

@Setter
private StructureToolItem.StructureData structureData;

public StructureToolScreen(StructureToolMenu menu, Inventory playerInventory, Component title) {
super(menu, playerInventory, title);
}

@Override
protected void init() {
super.init();
int offsetX = (this.width - this.imageWidth) / 2;
int offsetY = (this.height - this.imageHeight) / 2;

dataGenButton = addRenderableWidget(new ImageButton(offsetX + 122, offsetY + 21, 46, 16, SPRITES, button -> {
MultiblockRecipe recipe = toRecipe();
if (recipe != null) {
ItemStack result = recipe.getResult();
// "MultiblockRecipe.builder(\"%s\", %d)".formatted(BuiltInRegistries.ITEM.getKey(result.getItem()),
// result.getCount())
StringBuilder codeBuilder = new StringBuilder("MultiblockRecipe.builder(\"%s\", %d)"
.formatted(BuiltInRegistries.ITEM.getKey(result.getItem()), result.getCount()));
codeBuilder.append("\n");

for (List<String> layer : recipe.pattern.getLayers()) {
codeBuilder.append(" .layer(");
codeBuilder.append(layer.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")));
codeBuilder.append(")");
codeBuilder.append("\n");
}
recipe.pattern.getSymbols().forEach((symbol, predicate) -> {
codeBuilder.append(" .symbol(");
codeBuilder.append("'").append(symbol).append("'");
codeBuilder.append(", ");
if (predicate.getProperties().isEmpty()) {
codeBuilder.append("\"");
codeBuilder.append(BuiltInRegistries.BLOCK.getKey(predicate.getBlock()));
codeBuilder.append("\"");
codeBuilder.append(")");
} else {
codeBuilder.append("BlockPredicateWithState.of(");
codeBuilder.append(BuiltInRegistries.BLOCK.getKey(predicate.getBlock()));
codeBuilder.append(")");
codeBuilder.append("\n");
predicate.getProperties().forEach((stateName, stateValue) -> {
codeBuilder.append(" .hasState(");
codeBuilder.append("\"").append(stateName).append("\"");
codeBuilder.append(", ");
codeBuilder.append("\"").append(stateValue).append("\"");
codeBuilder.append("\n");
});
codeBuilder.append(" )");
}
codeBuilder.append("\n");
});
codeBuilder.append(" .save(provider);");
minecraft.keyboardHandler.setClipboard(codeBuilder.toString());
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.copied_to_clipboard"), false);
} else {
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.code_gen_filed")
.withStyle(ChatFormatting.RED),
false);
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.code_gen_check")
.withStyle(ChatFormatting.RED),
false);
}

minecraft.player.closeContainer();
}));
kubejsButton = addRenderableWidget(new ImageButton(offsetX + 122, offsetY + 37, 46, 16, SPRITES, button -> {
button.setFocused(false);
}));
jsonButton = addRenderableWidget(new ImageButton(offsetX + 122, offsetY + 53, 46, 16, SPRITES, button -> {
MultiblockRecipe recipe = toRecipe();
if (recipe != null) {
ItemStack result = recipe.getResult();
String pathString = getFilePath(
BuiltInRegistries.ITEM.getKey(result.getItem()).getPath(), "*.json");
if (pathString != null) {
Path path = Paths.get(pathString);
JsonElement json =
Recipe.CODEC.encodeStart(JsonOps.INSTANCE, recipe).getOrThrow();
try {
String jsonString = AnvilCraft.GSON.toJson(json);
Files.writeString(
path,
jsonString,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.file_saved", pathString), false);
} catch (IOException e) {
AnvilCraft.LOGGER.error("Saving {} has error", path, e);
minecraft.player.displayClientMessage(
Component.translatable(
"message.anvilcraft.file_save_failed", pathString, e.getMessage())
.withStyle(ChatFormatting.RED),
false);
}
} else {
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.no_file_selected")
.withStyle(ChatFormatting.RED),
false);
}
} else {
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.code_gen_filed")
.withStyle(ChatFormatting.RED),
false);
minecraft.player.displayClientMessage(
Component.translatable("message.anvilcraft.code_gen_check")
.withStyle(ChatFormatting.RED),
false);
}
minecraft.player.closeContainer();
}));
}

@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
super.render(guiGraphics, mouseX, mouseY, partialTick);
Expand Down Expand Up @@ -67,8 +219,25 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia
true);
pose.popPose();
}
// button render
// button text render
pose.pushPose();

pose.translate((this.width - this.imageWidth) / 2f, (this.height - this.imageHeight) / 2f, 0);
pose.scale(0.7F, 0.7F, 0.7F);

guiGraphics.drawString(
font,
Component.translatable("screen.anvilcraft.structure_tool.to_data_gen"),
177,
37,
0xFFFFFFFF,
true);
guiGraphics.drawString(
font, Component.translatable("screen.anvilcraft.structure_tool.to_kubejs"), 177, 60, 0xFFFFFFFF, true);
guiGraphics.drawString(
font, Component.translatable("screen.anvilcraft.structure_tool.to_json"), 177, 83, 0xFFFFFFFF, true);

pose.popPose();
}

@Override
Expand All @@ -77,4 +246,89 @@ protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX,
int j = (this.height - this.imageHeight) / 2;
guiGraphics.blit(CONTAINER_LOCATION, i, j, 0, 0, this.imageWidth, this.imageHeight);
}

@Nullable private static String getFilePath(String defaultName, String filter) {
try (MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer filterBuffer = stack.mallocPointer(1);
filterBuffer.put(stack.UTF8(filter));
filterBuffer.flip();
return TinyFileDialogs.tinyfd_saveFileDialog("Save", defaultName, filterBuffer, null);
}
}

@Nullable private MultiblockRecipe toRecipe() {
BlockPattern pattern = toBlockPattern();
ItemStack result = menu.slots.get(4 * 9).getItem().copy();
if (pattern != null && !result.isEmpty()) {
return new MultiblockRecipe(pattern, result);
}
return null;
}

@Nullable private BlockPattern toBlockPattern() {
ClientLevel level = minecraft.level;
if (structureData != null && level != null) {
BlockPattern pattern = BlockPattern.create();
currentSymbol = '@';
for (int y = structureData.getMinY(); y <= structureData.getMaxY(); y++) {
List<String> layer = new ArrayList<>();
for (int z = structureData.getMinZ(); z <= structureData.getMaxZ(); z++) {
StringBuilder sb = new StringBuilder();
for (int x = structureData.getMinX(); x <= structureData.getMaxX(); x++) {
BlockState state = level.getBlockState(new BlockPos(x, y, z));
if (state.is(Blocks.AIR)) {
sb.append(' ');
continue;
}
BlockPredicateWithState predicate = BlockPredicateWithState.of(state.getBlock());
if (state.hasProperty(BlockStateProperties.FACING)) {
predicate.hasState(
BlockStateProperties.FACING, state.getValue(BlockStateProperties.FACING));
}
if (state.hasProperty(BlockStateProperties.FACING_HOPPER)) {
predicate.hasState(
BlockStateProperties.FACING_HOPPER,
state.getValue(BlockStateProperties.FACING_HOPPER));
}
if (state.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) {
predicate.hasState(
BlockStateProperties.HORIZONTAL_FACING,
state.getValue(BlockStateProperties.HORIZONTAL_FACING));
}
if (state.hasProperty(BlockStateProperties.AXIS)) {
predicate.hasState(BlockStateProperties.AXIS, state.getValue(BlockStateProperties.AXIS));
}
if (state.hasProperty(BlockStateProperties.SLAB_TYPE)) {
predicate.hasState(
BlockStateProperties.SLAB_TYPE, state.getValue(BlockStateProperties.SLAB_TYPE));
}
if (state.hasProperty(BlockStateProperties.HALF)) {
predicate.hasState(BlockStateProperties.HALF, state.getValue(BlockStateProperties.HALF));
}
sb.append(getAndPutSymbol(pattern.getSymbols(), predicate));
}
layer.add(sb.toString());
}
pattern.layer(layer);
}
pattern.checkSymbols();
return pattern;
} else {
return null;
}
}

private char getAndPutSymbol(Map<Character, BlockPredicateWithState> symbols, BlockPredicateWithState predicate) {
if (symbols.entrySet().stream().noneMatch(e -> e.getValue().equals(predicate))) {
currentSymbol++;
symbols.put(currentSymbol, predicate);
} else {
for (Map.Entry<Character, BlockPredicateWithState> entry : symbols.entrySet()) {
if (entry.getValue().equals(predicate)) {
return entry.getKey();
}
}
}
return currentSymbol;
}
}
9 changes: 9 additions & 0 deletions src/main/java/dev/dubhe/anvilcraft/data/lang/OtherLang.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,14 @@ public static void init(@NotNull RegistrateLangProvider provider) {

provider.add("pack.anvilcraft.builtin_pack", "AnvilCraft Builtin ResourcePack");
provider.add("pack.anvilcraft.transparent_cauldron.description", "Transparent Cauldron");

provider.add("message.anvilcraft.copied_to_clipboard", "Copied to clipboard");
provider.add("message.anvilcraft.code_gen_filed", "Code generation failed");
provider.add(
"message.anvilcraft.code_gen_check",
"Please check if the selected area is a cube and if the output slot has items.");
provider.add("message.anvilcraft.no_file_selected", "No file path selected");
provider.add("message.anvilcraft.file_save_failed", "An issue occurred while saving file %s, %s");
provider.add("message.anvilcraft.file_saved", "File saved to %s");
}
}
Loading

0 comments on commit 1a30b97

Please sign in to comment.