diff --git a/src/main/java/dev/dubhe/anvilcraft/AnvilCraft.java b/src/main/java/dev/dubhe/anvilcraft/AnvilCraft.java index 4b31137e6..37d8660c6 100644 --- a/src/main/java/dev/dubhe/anvilcraft/AnvilCraft.java +++ b/src/main/java/dev/dubhe/anvilcraft/AnvilCraft.java @@ -6,11 +6,15 @@ import com.mojang.logging.LogUtils; import dev.dubhe.anvilcraft.api.events.EventManager; import dev.dubhe.anvilcraft.block.ModBlocks; +import dev.dubhe.anvilcraft.command.ModCommands; +import dev.dubhe.anvilcraft.config.AnvilCraftConfig; import dev.dubhe.anvilcraft.data.recipe.ModRecipeTypes; import dev.dubhe.anvilcraft.event.listener.AnvilEventListener; import dev.dubhe.anvilcraft.item.ModItems; import dev.dubhe.anvilcraft.log.Logger; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -21,6 +25,11 @@ import net.minecraft.world.level.block.Block; import org.jetbrains.annotations.NotNull; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; import java.util.Map; @SuppressWarnings("unused") @@ -29,6 +38,7 @@ public class AnvilCraft implements ModInitializer { public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); public static final Logger LOGGER = new Logger(LogUtils.getLogger()); public static final EventManager EVENT_BUS = new EventManager(); + public static AnvilCraftConfig config = new AnvilCraftConfig(); @Override public void onInitialize() { @@ -48,6 +58,28 @@ public void onInitialize() { if (null != entry.getValue().getSecond()) Registry.register(BuiltInRegistries.RECIPE_TYPE, AnvilCraft.of(entry.getKey()), entry.getValue().getSecond()); } + CommandRegistrationCallback.EVENT.register(ModCommands::register); + AnvilCraft.loadOrCreateConfig(); + } + + @SuppressWarnings("all") + public static void loadOrCreateConfig() { + Path commonConfigPath = FabricLoader.getInstance().getConfigDir().resolve("anvilcraft-common.json"); + File commonConfigFile = commonConfigPath.toFile(); + try { + if (!commonConfigFile.isFile()) { + commonConfigFile.createNewFile(); + try (FileWriter writer = new FileWriter(commonConfigFile)) { + AnvilCraft.GSON.toJson(AnvilCraft.config, writer); + } + } else { + try (FileReader reader = new FileReader(commonConfigFile)) { + AnvilCraft.config = AnvilCraft.GSON.fromJson(reader, AnvilCraftConfig.class); + } + } + } catch (IOException e) { + AnvilCraft.LOGGER.printStackTrace(e); + } } public static @NotNull ResourceLocation of(String id) { diff --git a/src/main/java/dev/dubhe/anvilcraft/command/AnvilCraftCommand.java b/src/main/java/dev/dubhe/anvilcraft/command/AnvilCraftCommand.java new file mode 100644 index 000000000..5f8bc177c --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/command/AnvilCraftCommand.java @@ -0,0 +1,20 @@ +package dev.dubhe.anvilcraft.command; + +import com.mojang.brigadier.CommandDispatcher; +import dev.dubhe.anvilcraft.AnvilCraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import org.jetbrains.annotations.NotNull; + +public class AnvilCraftCommand { + public static void register(@NotNull CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("anvilcraft") + .then(Commands.literal("config") + .then(Commands.literal("reload").executes(context -> { + AnvilCraft.loadOrCreateConfig(); + return 0; + })) + ) + ); + } +} diff --git a/src/main/java/dev/dubhe/anvilcraft/command/ModCommands.java b/src/main/java/dev/dubhe/anvilcraft/command/ModCommands.java new file mode 100644 index 000000000..cda8682e5 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/command/ModCommands.java @@ -0,0 +1,13 @@ +package dev.dubhe.anvilcraft.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; + +public class ModCommands { + @SuppressWarnings("unused") + public static void register(CommandDispatcher dispatcher, CommandBuildContext registryAccess, Commands.CommandSelection environment) { + AnvilCraftCommand.register(dispatcher); + } +} diff --git a/src/main/java/dev/dubhe/anvilcraft/config/AnvilCraftConfig.java b/src/main/java/dev/dubhe/anvilcraft/config/AnvilCraftConfig.java new file mode 100644 index 000000000..4d28739a1 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/config/AnvilCraftConfig.java @@ -0,0 +1,8 @@ +package dev.dubhe.anvilcraft.config; + +import com.google.gson.annotations.SerializedName; + +public class AnvilCraftConfig { + @SerializedName("anvil_efficiency") + public int anvilEfficiency = 64; +} diff --git a/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/item/ItemAnvilRecipe.java b/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/item/ItemAnvilRecipe.java index f3445ed2a..2021c7cd0 100644 --- a/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/item/ItemAnvilRecipe.java +++ b/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/item/ItemAnvilRecipe.java @@ -15,21 +15,16 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.item.FallingBlockEntity; import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.AnvilBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -96,12 +91,13 @@ public boolean matches(@NotNull ItemAnvilCraftingContainer container, Level leve return recipeItems.isEmpty() && compoundTagPredicates.isEmpty(); } - public void craft(@NotNull ItemAnvilCraftingContainer container, Level level) { + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean craft(@NotNull ItemAnvilCraftingContainer container, Level level) { BlockPos pos = new BlockPos(container.pos()); for (Component component : this.components) { pos = pos.below(); BlockState state = level.getBlockState(pos); - if (!component.test(state)) return; + if (!component.test(state)) return false; } pos = new BlockPos(container.pos()); if (this.location == Location.IN) pos = pos.below(); @@ -123,7 +119,7 @@ public void craft(@NotNull ItemAnvilCraftingContainer container, Level level) { itemStack.setCount(itemStack.getCount() - 1); } } - if (!recipeItems.isEmpty() || !compoundTagPredicates.isEmpty()) return; + if (!recipeItems.isEmpty() || !compoundTagPredicates.isEmpty()) return false; Map itemStackMap = new HashMap<>(); for (ItemEntity itemEntity : itemEntities) { itemStackMap.put(itemEntity.getItem(), itemEntity); @@ -143,14 +139,7 @@ public void craft(@NotNull ItemAnvilCraftingContainer container, Level level) { itemStackMap.get(itemStack).setItem(itemStack); } } - BlockPos resultPos = new BlockPos(container.pos()); - if (this.resultLocation == Location.IN) resultPos = resultPos.below(); - if (this.resultLocation == Location.UNDER) resultPos = resultPos.below(2); - Vec3 vec3 = resultPos.getCenter(); - ItemEntity entity = new ItemEntity(EntityType.ITEM, level); - entity.setItem(this.result.copy()); - entity.teleportRelative(vec3.x, vec3.y, vec3.z); - level.addFreshEntity(entity); + return true; } @Override diff --git a/src/main/java/dev/dubhe/anvilcraft/event/listener/AnvilEventListener.java b/src/main/java/dev/dubhe/anvilcraft/event/listener/AnvilEventListener.java index 558819299..225446e94 100644 --- a/src/main/java/dev/dubhe/anvilcraft/event/listener/AnvilEventListener.java +++ b/src/main/java/dev/dubhe/anvilcraft/event/listener/AnvilEventListener.java @@ -1,13 +1,18 @@ package dev.dubhe.anvilcraft.event.listener; +import dev.dubhe.anvilcraft.AnvilCraft; +import dev.dubhe.anvilcraft.api.events.SubscribeEvent; import dev.dubhe.anvilcraft.data.recipe.ModRecipeTypes; import dev.dubhe.anvilcraft.data.recipe.anvil.item.ItemAnvilRecipe; import dev.dubhe.anvilcraft.event.AnvilFallOnLandEvent; -import dev.dubhe.anvilcraft.api.events.SubscribeEvent; import dev.dubhe.anvilcraft.inventory.ItemAnvilCraftingContainer; +import net.minecraft.core.BlockPos; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import java.util.Optional; @@ -22,7 +27,32 @@ public void onLand(@NotNull AnvilFallOnLandEvent event) { Optional optional = server.getRecipeManager().getRecipeFor(ModRecipeTypes.ANVIL_ITEM, container, level); if (optional.isEmpty()) return; ItemAnvilRecipe recipe = optional.get(); - recipe.craft(container, level); + int counts = 0; + while (counts < AnvilCraft.config.anvilEfficiency) { + if (!recipe.craft(container, level)) break; + counts++; + } + ItemStack itemStack = recipe.getResultItem(level.registryAccess()).copy(); + int maxSize = itemStack.getItem().getMaxStackSize(); + counts = counts * itemStack.getCount(); + BlockPos resultPos = new BlockPos(container.pos()); + if (recipe.getResultLocation() == ItemAnvilRecipe.Location.IN) resultPos = resultPos.below(); + if (recipe.getResultLocation() == ItemAnvilRecipe.Location.UNDER) resultPos = resultPos.below(2); + Vec3 vec3 = resultPos.getCenter(); + for (int i = 0; i < counts / maxSize; i++) { + ItemStack stack = itemStack.copy(); + stack.setCount(maxSize); + ItemEntity entity = new ItemEntity(EntityType.ITEM, level); + entity.setItem(stack); + entity.teleportRelative(vec3.x, vec3.y, vec3.z); + level.addFreshEntity(entity); + } + ItemStack stack = itemStack.copy(); + stack.setCount(counts % maxSize); + ItemEntity entity = new ItemEntity(EntityType.ITEM, level); + entity.setItem(stack); + entity.teleportRelative(vec3.x, vec3.y, vec3.z); + level.addFreshEntity(entity); if (recipe.isAnvilDamage()) event.setAnvilDamage(true); } } diff --git a/src/main/java/dev/dubhe/anvilcraft/mixin/FallingBlockEntityMixin.java b/src/main/java/dev/dubhe/anvilcraft/mixin/FallingBlockEntityMixin.java index 423749b25..9101e588d 100644 --- a/src/main/java/dev/dubhe/anvilcraft/mixin/FallingBlockEntityMixin.java +++ b/src/main/java/dev/dubhe/anvilcraft/mixin/FallingBlockEntityMixin.java @@ -8,7 +8,6 @@ import net.minecraft.world.level.block.AnvilBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -21,16 +20,20 @@ public abstract class FallingBlockEntityMixin { @Shadow private BlockState blockState; + @Shadow private boolean cancelDrop; @Unique private final FallingBlockEntity ths = (FallingBlockEntity) (Object) this; - @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;"), locals = LocalCapture.CAPTURE_FAILHARD) - private void fallOn(CallbackInfo ci, Block block, BlockPos blockPos, boolean bl, boolean bl2, double d) { + @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) + private void anvilFallOnGround(CallbackInfo ci, Block block, BlockPos blockPos, boolean bl, boolean bl2, double d) { + if (ths.level().isClientSide()) return; if (!this.blockState.is(BlockTags.ANVIL)) return; AnvilFallOnLandEvent event = new AnvilFallOnLandEvent(ths.level(), blockPos, ths); AnvilCraft.EVENT_BUS.post(event); if (event.isAnvilDamage()) { - this.blockState = AnvilBlock.damage(this.blockState); + BlockState state = AnvilBlock.damage(this.blockState); + if (state != null) this.blockState = state; + else this.cancelDrop = true; } } }