diff --git a/build.gradle b/build.gradle index b30cc36..822f7f9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'net.minecraftforge.gradle' version '5.1.+' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' } @@ -26,6 +27,7 @@ minecraft { // Use non-default mappings at your own risk. They may not always work. // Simply re-run your setup task after changing the mappings to update your workspace. mappings channel: 'official', version: '1.18.2' + mappings channel: 'parchment', version: '2022.08.02-1.18.2' // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') diff --git a/settings.gradle b/settings.gradle index 2fb1a36..a95fa32 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ pluginManagement { repositories { gradlePluginPortal() maven { url = 'https://maven.minecraftforge.net/' } + maven { url = 'https://maven.parchmentmc.org' } } } diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache new file mode 100644 index 0000000..90a88d4 --- /dev/null +++ b/src/generated/resources/.cache/cache @@ -0,0 +1,7 @@ +b61bd40379af029dc4a8918675a5340d82eb9614 assets/enchantrium/blockstates/enchanter.json +12c47b4ceba86e32ead7ed95c8cf1ebdf6097490 assets/enchantrium/lang/en_us.json +612cfe324c0a8f894098e57a492a11ea7a7af881 assets/enchantrium/models/block/enchanter.json +b3795796d7640d926777c42c84f36a561511f981 assets/enchantrium/models/item/enchanter.json +b5996790803bc6c5aa9e19868571b94ff2770cc8 assets/enchantrium/models/item/test_item.json +0dfde33a6966e8ce59687aa186ad4ae43952e3cc data/enchantrium/advancements/recipes/enchantrium/enchanter.json +2feeac4086afc49c70948894d952479c375c10e3 data/enchantrium/recipes/enchanter.json diff --git a/src/generated/resources/assets/enchantrium/blockstates/enchanter.json b/src/generated/resources/assets/enchantrium/blockstates/enchanter.json new file mode 100644 index 0000000..1dd9a69 --- /dev/null +++ b/src/generated/resources/assets/enchantrium/blockstates/enchanter.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "enchantrium:block/enchanter" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/enchantrium/lang/en_us.json b/src/generated/resources/assets/enchantrium/lang/en_us.json new file mode 100644 index 0000000..16883c9 --- /dev/null +++ b/src/generated/resources/assets/enchantrium/lang/en_us.json @@ -0,0 +1,5 @@ +{ + "block.enchantrium.enchanter": "Enchanter", + "item.enchantrium.test_item": "Test Item :)", + "itemGroup.enchantrium": "Enchantrium" +} \ No newline at end of file diff --git a/src/generated/resources/assets/enchantrium/models/block/enchanter.json b/src/generated/resources/assets/enchantrium/models/block/enchanter.json new file mode 100644 index 0000000..5b5f58f --- /dev/null +++ b/src/generated/resources/assets/enchantrium/models/block/enchanter.json @@ -0,0 +1,11 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "down": "enchantrium:block/enchanter_side", + "up": "enchantrium:block/enchanter_top", + "north": "enchantrium:block/enchanter_side", + "south": "enchantrium:block/enchanter_side", + "east": "enchantrium:block/enchanter_side", + "west": "enchantrium:block/enchanter_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/enchantrium/models/item/enchanter.json b/src/generated/resources/assets/enchantrium/models/item/enchanter.json new file mode 100644 index 0000000..740ed45 --- /dev/null +++ b/src/generated/resources/assets/enchantrium/models/item/enchanter.json @@ -0,0 +1,3 @@ +{ + "parent": "enchantrium:block/enchanter" +} \ No newline at end of file diff --git a/src/generated/resources/assets/enchantrium/models/item/test_item.json b/src/generated/resources/assets/enchantrium/models/item/test_item.json new file mode 100644 index 0000000..1464594 --- /dev/null +++ b/src/generated/resources/assets/enchantrium/models/item/test_item.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "enchantrium:item/test_item" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/enchantrium/advancements/recipes/enchantrium/enchanter.json b/src/generated/resources/data/enchantrium/advancements/recipes/enchantrium/enchanter.json new file mode 100644 index 0000000..1654d64 --- /dev/null +++ b/src/generated/resources/data/enchantrium/advancements/recipes/enchantrium/enchanter.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "enchantrium:enchanter" + ] + }, + "criteria": { + "enchanting": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:enchanting_table" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "enchantrium:enchanter" + } + } + }, + "requirements": [ + [ + "enchanting", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/enchantrium/recipes/enchanter.json b/src/generated/resources/data/enchantrium/recipes/enchanter.json new file mode 100644 index 0000000..e733561 --- /dev/null +++ b/src/generated/resources/data/enchantrium/recipes/enchanter.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "xxx", + "x#x", + "#y#" + ], + "key": { + "x": { + "tag": "forge:gems/diamond" + }, + "#": { + "tag": "forge:storage_blocks/copper" + }, + "y": { + "item": "minecraft:enchanting_table" + } + }, + "result": { + "item": "enchantrium:enchanter" + } +} \ No newline at end of file diff --git a/src/main/java/xyz/nuark/enchantrium/Enchantrium.java b/src/main/java/xyz/nuark/enchantrium/Enchantrium.java index f77445e..f3013de 100644 --- a/src/main/java/xyz/nuark/enchantrium/Enchantrium.java +++ b/src/main/java/xyz/nuark/enchantrium/Enchantrium.java @@ -1,77 +1,29 @@ package xyz.nuark.enchantrium; import com.mojang.logging.LogUtils; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.InterModComms; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; -import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; -import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.slf4j.Logger; +import xyz.nuark.enchantrium.setup.ClientSetup; +import xyz.nuark.enchantrium.setup.ModSetup; +import xyz.nuark.enchantrium.setup.Registration; -import java.util.stream.Collectors; - -// The value here should match an entry in the META-INF/mods.toml file -@Mod("enchantrium") +@Mod(Enchantrium.MOD_ID) public class Enchantrium { + public static final String MOD_ID = "enchantrium"; + public static final Logger LOGGER = LogUtils.getLogger(); - // Directly reference a slf4j logger - private static final Logger LOGGER = LogUtils.getLogger(); public Enchantrium() { - // Register the setup method for modloading - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); - // Register the enqueueIMC method for modloading - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC); - // Register the processIMC method for modloading - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC); + IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus(); - // Register ourselves for server and other game events we are interested in - MinecraftForge.EVENT_BUS.register(this); - } + ModSetup.setup(); + Registration.register(eventBus); - private void setup(final FMLCommonSetupEvent event) { - // Some preinit code - LOGGER.info("HELLO FROM PREINIT"); - LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName()); - } - - private void enqueueIMC(final InterModEnqueueEvent event) { - // Some example code to dispatch IMC to another mod - InterModComms.sendTo("enchantrium", "helloworld", () -> { - LOGGER.info("Hello world from the MDK"); - return "Hello world"; - }); - } - - private void processIMC(final InterModProcessEvent event) { - // Some example code to receive and process InterModComms from other mods - LOGGER.info("Got IMC {}", event.getIMCStream(). - map(m -> m.messageSupplier().get()). - collect(Collectors.toList())); - } - - // You can use SubscribeEvent and let the Event Bus discover methods to call - @SubscribeEvent - public void onServerStarting(ServerStartingEvent event) { - // Do something when the server starts - LOGGER.info("HELLO from server starting"); - } - - // You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD - // Event bus for receiving Registry Events) - @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) - public static class RegistryEvents { - @SubscribeEvent - public static void onBlocksRegistry(final RegistryEvent.Register blockRegistryEvent) { - // Register a new block here - LOGGER.info("HELLO from Register Block"); - } + eventBus.addListener(ModSetup::init); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> eventBus.addListener(ClientSetup::init)); } } diff --git a/src/main/java/xyz/nuark/enchantrium/block/ModBlocks.java b/src/main/java/xyz/nuark/enchantrium/block/ModBlocks.java new file mode 100644 index 0000000..c5fe051 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/block/ModBlocks.java @@ -0,0 +1,65 @@ +package xyz.nuark.enchantrium.block; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.custom.EnchanterBlock; +import xyz.nuark.enchantrium.item.ModItems; +import xyz.nuark.enchantrium.setup.ModSetup; + +import java.util.List; +import java.util.function.Supplier; + +public class ModBlocks { + public static final DeferredRegister BLOCKS = + DeferredRegister.create(ForgeRegistries.BLOCKS, Enchantrium.MOD_ID); + + public static final RegistryObject ENCHANTER = registerBlockWithoutBlockItem("enchanter", EnchanterBlock::new); + + private static RegistryObject registerBlockWithoutBlockItem(String name, Supplier block) { + return BLOCKS.register(name, block); + } + + private static RegistryObject registerBlock(String name, Supplier block, String tooltipKey) { + RegistryObject toReturn = BLOCKS.register(name, block); + registerBlockItem(name, toReturn, tooltipKey); + return toReturn; + } + + private static RegistryObject registerBlockItem(String name, RegistryObject block, String tooltipKey) { + return ModItems.ITEMS.register(name, () -> new BlockItem(block.get(), + new Item.Properties().tab(ModSetup.ITEM_GROUP)) { + @Override + public void appendHoverText(@NotNull ItemStack pStack, @Nullable Level pLevel, @NotNull List pTooltip, @NotNull TooltipFlag pFlag) { + pTooltip.add(new TranslatableComponent(tooltipKey)); + } + }); + } + + private static RegistryObject registerBlock(String name, Supplier block) { + RegistryObject toReturn = BLOCKS.register(name, block); + registerBlockItem(name, toReturn); + return toReturn; + } + + private static RegistryObject registerBlockItem(String name, RegistryObject block) { + return ModItems.ITEMS.register(name, () -> new BlockItem(block.get(), + new Item.Properties().tab(ModSetup.ITEM_GROUP))); + } + + public static void register(IEventBus eventBus) { + BLOCKS.register(eventBus); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/block/custom/EnchanterBlock.java b/src/main/java/xyz/nuark/enchantrium/block/custom/EnchanterBlock.java new file mode 100644 index 0000000..318b538 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/block/custom/EnchanterBlock.java @@ -0,0 +1,63 @@ +package xyz.nuark.enchantrium.block.custom; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.network.NetworkHooks; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity; + +public class EnchanterBlock extends BaseEntityBlock { + public EnchanterBlock() { + super(BlockBehaviour.Properties.of(Material.STONE).strength(2f).lightLevel((p_187435_) -> 14).sound(SoundType.STONE)); + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.MODEL; + } + + @Override + public void onRemove(BlockState pState, @NotNull Level pLevel, @NotNull BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + if (pState.getBlock() != pNewState.getBlock()) { + BlockEntity blockEntity = pLevel.getBlockEntity(pPos); + if (blockEntity instanceof EnchanterBlockEntity) { + ((EnchanterBlockEntity) blockEntity).drops(); + } + } + super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); + } + + @Override + public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, + Player player, InteractionHand interactionHand, BlockHitResult hitResult) { + if (!level.isClientSide()) { + BlockEntity entity = level.getBlockEntity(blockPos); + if (entity instanceof EnchanterBlockEntity) { + NetworkHooks.openGui(((ServerPlayer) player), (EnchanterBlockEntity) entity, blockPos); + } else { + throw new IllegalStateException("Our Container provider is missing!"); + } + } + + return InteractionResult.sidedSuccess(level.isClientSide()); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(@NotNull BlockPos blockPos, @NotNull BlockState blockState) { + return new EnchanterBlockEntity(blockPos, blockState); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/block/entity/ModBlockEntities.java b/src/main/java/xyz/nuark/enchantrium/block/entity/ModBlockEntities.java new file mode 100644 index 0000000..4b963c3 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/block/entity/ModBlockEntities.java @@ -0,0 +1,22 @@ +package xyz.nuark.enchantrium.block.entity; + +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.ModBlocks; +import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity; + +public class ModBlockEntities { + public static final DeferredRegister> BLOCK_ENTITIES = + DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, Enchantrium.MOD_ID); + + public static final RegistryObject> ENCHANTER_BLOCK_ENTITY = + BLOCK_ENTITIES.register("enchanter_block_entity", () -> BlockEntityType.Builder.of(EnchanterBlockEntity::new, ModBlocks.ENCHANTER.get()).build(null)); + + public static void register(IEventBus eventBus) { + BLOCK_ENTITIES.register(eventBus); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/block/entity/custom/EnchanterBlockEntity.java b/src/main/java/xyz/nuark/enchantrium/block/entity/custom/EnchanterBlockEntity.java new file mode 100644 index 0000000..f598c45 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/block/entity/custom/EnchanterBlockEntity.java @@ -0,0 +1,129 @@ +package xyz.nuark.enchantrium.block.entity.custom; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.Containers; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.ItemStackHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.entity.ModBlockEntities; +import xyz.nuark.enchantrium.screen.EnchanterMenu; +import xyz.nuark.enchantrium.util.EnchantmentUtil; + +import java.util.List; + +public class EnchanterBlockEntity extends BlockEntity implements MenuProvider { + private final ItemStackHandler itemHandler = new ItemStackHandler(3) { + @Override + protected void onContentsChanged(int slot) { + setChanged(); + } + }; + + private LazyOptional lazyItemHandler = LazyOptional.empty(); + + public EnchanterBlockEntity(BlockPos pos, BlockState blockState) { + super(ModBlockEntities.ENCHANTER_BLOCK_ENTITY.get(), pos, blockState); + } + + @Override + public @NotNull Component getDisplayName() { + return new TextComponent("Enchanter"); + } + + @Nullable + @Override + public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player player) { + return new EnchanterMenu(containerID, inventory, this); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @javax.annotation.Nullable Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return lazyItemHandler.cast(); + } + + return super.getCapability(cap, side); + } + + @Override + public void onLoad() { + super.onLoad(); + lazyItemHandler = LazyOptional.of(() -> itemHandler); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + lazyItemHandler.invalidate(); + } + + @Override + protected void saveAdditional(@NotNull CompoundTag tag) { + tag.put("inventory", itemHandler.serializeNBT()); + super.saveAdditional(tag); + } + + @Override + public void load(@NotNull CompoundTag nbt) { + super.load(nbt); + itemHandler.deserializeNBT(nbt.getCompound("inventory")); + } + + public void drops() { + SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots()); + for (int i = 0; i < itemHandler.getSlots(); i++) { + inventory.setItem(i, itemHandler.getStackInSlot(i)); + } + + if (this.level != null) { + Containers.dropContents(this.level, this.worldPosition, inventory); + } else { + Enchantrium.LOGGER.error("EnchanterBlockEntity.drops() - level is null"); + } + } + + public ItemStack getInput() { + return itemHandler.getStackInSlot(0); + } + + public ItemStack getEmeralds() { + return itemHandler.getStackInSlot(1); + } + + public ItemStack getNetherite() { + return itemHandler.getStackInSlot(2); + } + + public boolean enchant(List enchantments, EnchantmentUtil.EnchantmentCost enchantmentCost, boolean setUnbreakable) { + ItemStack input = itemHandler.extractItem(0, 1, false); + itemHandler.extractItem(1, enchantmentCost.lapis(), false); + itemHandler.extractItem(2, enchantmentCost.netherite(), false); + for (EnchantmentInstance enchantment : enchantments) { + input.enchant(enchantment.enchantment, enchantment.level); + } + input.getOrCreateTag().putBoolean("Unbreakable", setUnbreakable); + + itemHandler.setStackInSlot(0, input); + itemHandler.insertItem(0, input, false); + + return true; + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/datagen/BlockStatesGenerator.java b/src/main/java/xyz/nuark/enchantrium/datagen/BlockStatesGenerator.java new file mode 100644 index 0000000..a28cfb0 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/datagen/BlockStatesGenerator.java @@ -0,0 +1,25 @@ +package xyz.nuark.enchantrium.datagen; + +import net.minecraft.data.DataGenerator; +import net.minecraftforge.client.model.generators.BlockStateProvider; +import net.minecraftforge.common.data.ExistingFileHelper; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.ModBlocks; + +public class BlockStatesGenerator extends BlockStateProvider { + public BlockStatesGenerator(DataGenerator gen, ExistingFileHelper exFileHelper) { + super(gen, Enchantrium.MOD_ID, exFileHelper); + } + + @Override + protected void registerStatesAndModels() { + registerEnchanter(); + } + + private void registerEnchanter() { + var block = ModBlocks.ENCHANTER.get(); + var side = modLoc("block/enchanter_side"); + var top = modLoc("block/enchanter_top"); + simpleBlock(block, models().cube(block.getRegistryName().getPath(), side, top, side, side, side, side)); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/datagen/DataGenerators.java b/src/main/java/xyz/nuark/enchantrium/datagen/DataGenerators.java new file mode 100644 index 0000000..2c40d98 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/datagen/DataGenerators.java @@ -0,0 +1,23 @@ +package xyz.nuark.enchantrium.datagen; + +import net.minecraft.data.DataGenerator; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; +import xyz.nuark.enchantrium.Enchantrium; + +@Mod.EventBusSubscriber(modid = Enchantrium.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class DataGenerators { + @SubscribeEvent + public static void gatherData(GatherDataEvent event) { + DataGenerator generator = event.getGenerator(); + if (event.includeServer()) { + generator.addProvider(new RecipesGenerator(generator)); + } + if (event.includeClient()) { + generator.addProvider(new BlockStatesGenerator(generator, event.getExistingFileHelper())); + generator.addProvider(new ItemModelGenerator(generator, event.getExistingFileHelper())); + generator.addProvider(new LanguageGenerator(generator, "en_us")); + } + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/datagen/ItemModelGenerator.java b/src/main/java/xyz/nuark/enchantrium/datagen/ItemModelGenerator.java new file mode 100644 index 0000000..f32e3ab --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/datagen/ItemModelGenerator.java @@ -0,0 +1,19 @@ +package xyz.nuark.enchantrium.datagen; + +import net.minecraft.data.DataGenerator; +import net.minecraftforge.client.model.generators.ItemModelProvider; +import net.minecraftforge.common.data.ExistingFileHelper; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.item.ModItems; + +public class ItemModelGenerator extends ItemModelProvider { + public ItemModelGenerator(DataGenerator generator, ExistingFileHelper exFileHelper) { + super(generator, Enchantrium.MOD_ID, exFileHelper); + } + + @Override + protected void registerModels() { + basicItem(ModItems.TEST_ITEM.get()); + withExistingParent(ModItems.ENCHANTER_ITEM.get().getRegistryName().getPath(), modLoc("block/enchanter")); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/datagen/LanguageGenerator.java b/src/main/java/xyz/nuark/enchantrium/datagen/LanguageGenerator.java new file mode 100644 index 0000000..dd49ed6 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/datagen/LanguageGenerator.java @@ -0,0 +1,21 @@ +package xyz.nuark.enchantrium.datagen; + +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.LanguageProvider; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.ModBlocks; +import xyz.nuark.enchantrium.item.ModItems; + +public class LanguageGenerator extends LanguageProvider { + public LanguageGenerator(DataGenerator gen, String locale) { + super(gen, Enchantrium.MOD_ID, locale); + } + + @Override + protected void addTranslations() { + add("itemGroup." + Enchantrium.MOD_ID, "Enchantrium"); + + add(ModBlocks.ENCHANTER.get(), "Enchanter"); + add(ModItems.TEST_ITEM.get(), "Test Item :)"); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/datagen/RecipesGenerator.java b/src/main/java/xyz/nuark/enchantrium/datagen/RecipesGenerator.java new file mode 100644 index 0000000..8daa4bf --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/datagen/RecipesGenerator.java @@ -0,0 +1,32 @@ +package xyz.nuark.enchantrium.datagen; + +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.world.item.Items; +import net.minecraftforge.common.Tags; +import org.jetbrains.annotations.NotNull; +import xyz.nuark.enchantrium.block.ModBlocks; + +import java.util.function.Consumer; + +public class RecipesGenerator extends RecipeProvider { + public RecipesGenerator(DataGenerator generator) { + super(generator); + } + + @Override + protected void buildCraftingRecipes(@NotNull Consumer consumer) { + ShapedRecipeBuilder.shaped(ModBlocks.ENCHANTER.get()) + .pattern("xxx") + .pattern("x#x") + .pattern("#y#") + .define('x', Tags.Items.GEMS_DIAMOND) + .define('#', Tags.Items.STORAGE_BLOCKS_COPPER) + .define('y', Items.ENCHANTING_TABLE) + .unlockedBy("enchanting", InventoryChangeTrigger.TriggerInstance.hasItems(Items.ENCHANTING_TABLE)) + .save(consumer); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/item/ModItems.java b/src/main/java/xyz/nuark/enchantrium/item/ModItems.java new file mode 100644 index 0000000..5ceefac --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/item/ModItems.java @@ -0,0 +1,27 @@ +package xyz.nuark.enchantrium.item; + +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.block.ModBlocks; +import xyz.nuark.enchantrium.setup.ModSetup; + +public class ModItems { + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Enchantrium.MOD_ID); + + public static final RegistryObject TEST_ITEM = ITEMS.register("test_item", () -> new Item(new Item.Properties().tab(ModSetup.ITEM_GROUP))); + public static final RegistryObject ENCHANTER_ITEM = fromBlock(ModBlocks.ENCHANTER); + + public static void register(IEventBus eventBus) { + ITEMS.register(eventBus); + } + + public static RegistryObject fromBlock(RegistryObject block) { + return ITEMS.register(block.getId().getPath(), () -> new BlockItem(block.get(), new Item.Properties().tab(ModSetup.ITEM_GROUP))); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/network/Networking.java b/src/main/java/xyz/nuark/enchantrium/network/Networking.java new file mode 100644 index 0000000..3bf0e25 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/network/Networking.java @@ -0,0 +1,44 @@ +package xyz.nuark.enchantrium.network; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.simple.SimpleChannel; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.network.message.PacketEnchantItem; + +public class Networking { + public static final String PROTOCOL_VERSION = "1"; + public static SimpleChannel INSTANCE; + + private static int packetId = 0; + private static int nextPacketId() { + return packetId++; + } + + public static void register() { + INSTANCE = NetworkRegistry.ChannelBuilder + .named(new ResourceLocation(Enchantrium.MOD_ID, "main")) + .networkProtocolVersion(() -> PROTOCOL_VERSION) + .clientAcceptedVersions(PROTOCOL_VERSION::equals) + .serverAcceptedVersions(PROTOCOL_VERSION::equals) + .simpleChannel(); + + INSTANCE.messageBuilder(PacketEnchantItem.class, nextPacketId(), NetworkDirection.PLAY_TO_SERVER) + .encoder(PacketEnchantItem::encode) + .decoder(PacketEnchantItem::decode) + .consumer(PacketEnchantItem::handle) + .add(); + } + + + public static void sendToServer(MSG message) { + INSTANCE.sendToServer(message); + } + + public static void sendToPlayer(MSG message, ServerPlayer player) { + INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/network/message/PacketEnchantItem.java b/src/main/java/xyz/nuark/enchantrium/network/message/PacketEnchantItem.java new file mode 100644 index 0000000..efbbf7c --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/network/message/PacketEnchantItem.java @@ -0,0 +1,65 @@ +package xyz.nuark.enchantrium.network.message; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.registries.ForgeRegistries; +import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity; +import xyz.nuark.enchantrium.util.EnchantmentUtil; + +import java.util.List; +import java.util.function.Supplier; + +public class PacketEnchantItem { + private final BlockPos blockEntityPos; + private final List enchantments; + private final EnchantmentUtil.EnchantmentCost enchantmentCost; + private final boolean unbreakingSet; + + public PacketEnchantItem(BlockPos blockEntityPos, List enchantments, EnchantmentUtil.EnchantmentCost enchantmentCost, boolean unbreakingSet) { + this.blockEntityPos = blockEntityPos; + this.enchantments = enchantments; + this.enchantmentCost = enchantmentCost; + this.unbreakingSet = unbreakingSet; + } + + public boolean handle(Supplier supplier) { + NetworkEvent.Context ctx = supplier.get(); + ctx.enqueueWork(() -> { + EnchanterBlockEntity ebe = (EnchanterBlockEntity)ctx.getSender().level.getBlockEntity(blockEntityPos); + if (ebe.enchant(enchantments, enchantmentCost, unbreakingSet)) { + ctx.getSender().giveExperienceLevels(-enchantmentCost.levels()); + } + }); + return true; + } + + public void encode(FriendlyByteBuf friendlyByteBuf) { + friendlyByteBuf.writeBlockPos(blockEntityPos); + friendlyByteBuf.writeCollection(enchantments, (buf, enchantment) -> { + buf.writeResourceLocation(ForgeRegistries.ENCHANTMENTS.getKey(enchantment.enchantment)); + buf.writeVarInt(enchantment.level); + }); + friendlyByteBuf.writeVarInt(enchantmentCost.levels()); + friendlyByteBuf.writeVarInt(enchantmentCost.lapis()); + friendlyByteBuf.writeVarInt(enchantmentCost.netherite()); + friendlyByteBuf.writeBoolean(unbreakingSet); + } + + public static PacketEnchantItem decode(FriendlyByteBuf friendlyByteBuf) { + return new PacketEnchantItem( + friendlyByteBuf.readBlockPos(), + friendlyByteBuf.readList((buf) -> new EnchantmentInstance( + ForgeRegistries.ENCHANTMENTS.getValue(buf.readResourceLocation()), + buf.readVarInt() + )), + new EnchantmentUtil.EnchantmentCost( + friendlyByteBuf.readVarInt(), + friendlyByteBuf.readVarInt(), + friendlyByteBuf.readVarInt() + ), + friendlyByteBuf.readBoolean() + ); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/screen/EnchanterMenu.java b/src/main/java/xyz/nuark/enchantrium/screen/EnchanterMenu.java new file mode 100644 index 0000000..5f28a86 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/screen/EnchanterMenu.java @@ -0,0 +1,209 @@ +package xyz.nuark.enchantrium.screen; + +import com.google.common.collect.Lists; +import net.minecraft.Util; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.Tags; +import net.minecraftforge.items.CapabilityItemHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.nuark.enchantrium.block.ModBlocks; +import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity; +import xyz.nuark.enchantrium.network.Networking; +import xyz.nuark.enchantrium.network.message.PacketEnchantItem; +import xyz.nuark.enchantrium.screen.slot.FilteredSlot; +import xyz.nuark.enchantrium.util.EnchantmentUtil; + +import java.util.List; + +public class EnchanterMenu extends AbstractContainerMenu { + private final EnchanterBlockEntity blockEntity; + private final Level level; + + private ItemStack inputStack = new ItemStack(Items.AIR); + private List enchantments = Lists.newArrayList(); + private boolean unbreakingSet = false; + private int currentEnchantmentIndex = -1; + private final Object lock = new Object(); + + public EnchanterMenu(int containerId, Inventory inv, FriendlyByteBuf extraData) { + this(containerId, inv, inv.player.level.getBlockEntity(extraData.readBlockPos())); + } + + public EnchanterMenu(int containerId, Inventory inv, BlockEntity entity) { + super(ModMenuTypes.ENCHANTER_MENU.get(), containerId); + checkContainerSize(inv, 3); + blockEntity = ((EnchanterBlockEntity) entity); + this.level = inv.player.level; + + addPlayerInventory(inv); + addPlayerHotbar(inv); + + this.blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(handler -> { + this.addSlot(new FilteredSlot( + handler, 0, 8, 19, + stack -> EnchantmentUtil.canBeEnchanted(stack) && !stack.isEnchanted() && !stack.is(Items.BOOK) + )); + this.addSlot(new FilteredSlot( + handler, 1, 31, 19, + stack -> stack.is(Tags.Items.STORAGE_BLOCKS_LAPIS) + )); + this.addSlot(new FilteredSlot( + handler, 2, 54, 19, + stack -> stack.is(Tags.Items.INGOTS_NETHERITE) + )); + }); + } + + @Nullable + public EnchantmentInstance getCurrentEnchantment() { + synchronized (lock) { + if (blockEntity.getInput().isEmpty() || blockEntity.getInput().isEnchanted()) { + currentEnchantmentIndex = -1; + return null; + } else if (currentEnchantmentIndex == -1) { + currentEnchantmentIndex = 0; + } + if (!this.inputStack.sameItem(blockEntity.getInput())) { + this.enchantments = EnchantmentUtil.getApplicableEnchantments(blockEntity.getInput()); + currentEnchantmentIndex = 0; + this.inputStack = blockEntity.getInput(); + } + return this.enchantments.size() > 0 ? this.enchantments.get(currentEnchantmentIndex) : null; + } + } + + public boolean unbreakable() { + return unbreakingSet; + } + + public EnchantmentUtil.EnchantmentCost getEnchantmentRequirements() { + return EnchantmentUtil.calculateEnchantmentPrice(this.enchantments.stream().filter(e -> e.level > 0).toList(), unbreakingSet); + } + + public boolean requirementsMet(Player player, EnchantmentUtil.EnchantmentCost enchantmentRequirements) { + return player.experienceLevel >= enchantmentRequirements.levels() + && blockEntity.getEmeralds().getCount() >= enchantmentRequirements.lapis() + && blockEntity.getNetherite().getCount() >= enchantmentRequirements.netherite(); + } + + @Override + public boolean clickMenuButton(Player player, int buttonId) { + if (buttonId < 0 || buttonId >= 6) { + Util.logAndPauseIfInIde(player.getName() + " pressed invalid button id: " + buttonId); + return false; + } + + synchronized (lock) { + if (buttonId == 0) { + var enchantments = this.enchantments.stream().filter(e -> e.level > 0).toList(); + if (enchantments.isEmpty()) return true; + Networking.sendToServer(new PacketEnchantItem( + blockEntity.getBlockPos(), + enchantments, + getEnchantmentRequirements(), + unbreakingSet + )); + } else if (buttonId == 1) { + currentEnchantmentIndex = (currentEnchantmentIndex - 1 + enchantments.size()) % enchantments.size(); + } else if (buttonId == 2) { + currentEnchantmentIndex = (currentEnchantmentIndex + 1) % enchantments.size(); + } else if (buttonId == 3) { + var enchantment = this.enchantments.get(currentEnchantmentIndex); + this.enchantments.set(currentEnchantmentIndex, new EnchantmentInstance( + enchantment.enchantment, + enchantment.level > 0 ? (enchantment.level - 1) : 0 + )); + } else if (buttonId == 4) { + var enchantment = this.enchantments.get(currentEnchantmentIndex); + this.enchantments.set(currentEnchantmentIndex, new EnchantmentInstance( + enchantment.enchantment, + enchantment.level < enchantment.enchantment.getMaxLevel() ? (enchantment.level + 1) : enchantment.level + )); + } else { + unbreakingSet = !unbreakingSet; + } + } + return true; + } + + @Override + public boolean stillValid(@NotNull Player player) { + return stillValid(ContainerLevelAccess.create(level, blockEntity.getBlockPos()), player, ModBlocks.ENCHANTER.get()); + } + + private void addPlayerInventory(Inventory playerInventory) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 150 + i * 18)); + } + } + } + + private void addPlayerHotbar(Inventory playerInventory) { + for (int i = 0; i < 9; i++) { + addSlot(new Slot(playerInventory, i, 8 + i * 18, 208)); + } + } + + // CREDIT GOES TO: diesieben07 | https://github.com/diesieben07/SevenCommons + // must assign a slot number to each of the slots used by the GUI. + // For this container, we can see both the tile inventory's slots and the player inventory slots and the hotbar. + // Each time we add a Slot to the container, it automatically increases the slotIndex, which means + // 0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers 0 - 8) + // 9 - 35 = player inventory slots (which map to the InventoryPlayer slot numbers 9 - 35) + // 36 - 44 = TileInventory slots, which map to our TileEntity slot numbers 0 - 8) + private static final int HOTBAR_SLOT_COUNT = 9; + private static final int PLAYER_INVENTORY_ROW_COUNT = 3; + private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9; + private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT; + private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT; + private static final int VANILLA_FIRST_SLOT_INDEX = 0; + private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT; + + // THIS YOU HAVE TO DEFINE! + private static final int TE_INVENTORY_SLOT_COUNT = 3; // must be the number of slots you have! + + @Override + public @NotNull ItemStack quickMoveStack(@NotNull Player playerIn, int index) { + Slot sourceSlot = slots.get(index); + if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM + ItemStack sourceStack = sourceSlot.getItem(); + ItemStack copyOfSourceStack = sourceStack.copy(); + + // Check if the slot clicked is one of the vanilla container slots + if (index < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) { + // This is a vanilla container slot so merge the stack into the tile inventory + if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX + + TE_INVENTORY_SLOT_COUNT, false)) { + return ItemStack.EMPTY; // EMPTY_ITEM + } + } else if (index < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) { + // This is a TE slot so merge the stack into the players inventory + if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) { + return ItemStack.EMPTY; + } + } else { + System.out.println("Invalid slotIndex:" + index); + return ItemStack.EMPTY; + } + // If stack size == 0 (the entire stack was moved) set slot contents to null + if (sourceStack.getCount() == 0) { + sourceSlot.set(ItemStack.EMPTY); + } else { + sourceSlot.setChanged(); + } + sourceSlot.onTake(playerIn, sourceStack); + return copyOfSourceStack; + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/screen/EnchanterScreen.java b/src/main/java/xyz/nuark/enchantrium/screen/EnchanterScreen.java new file mode 100644 index 0000000..9d64076 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/screen/EnchanterScreen.java @@ -0,0 +1,175 @@ +package xyz.nuark.enchantrium.screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.NotNull; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.screen.widget.Label; + +public class EnchanterScreen extends AbstractContainerScreen { + private static final ResourceLocation TEXTURE = + new ResourceLocation(Enchantrium.MOD_ID, "textures/gui/enchanter_gui.png"); + + private Label currentEnchantmentLabel; + private Button enchantBtn; + private Button nextBtn; + private Button prevBtn; + private Button increaseLevelBtn; + private Button decreaseLevelBtn; + private Button switchUnbreakableBtn; + + public EnchanterScreen(EnchanterMenu enchanterMenu, Inventory inventory, Component title) { + super(enchanterMenu, inventory, title); + + imageWidth = 176; + imageHeight = 232; + } + + @Override + protected void init() { + super.init(); + + int sx = width / 2 - imageWidth / 2; + int sy = height / 2 - imageHeight / 2; + + currentEnchantmentLabel = new Label( + new TextComponent(""), + sx + 7, sy + 51, 0xFFFFFF, false + ); + + enchantBtn = new Button( + sx + 76, sy + 18, 93, 20, + new TextComponent("Enchant"), + button -> clickButton(0) + ); + + prevBtn = new Button( + sx + 7, sy + 71, 78, 20, + new TextComponent("Previous"), + button -> clickButton(1) + ); + nextBtn = new Button( + sx + 91, sy + 71, 78, 20, + new TextComponent("Next"), + button -> clickButton(2) + ); + + decreaseLevelBtn = new Button( + sx + 7, sy + 97, 78, 20, + new TextComponent("Decrease"), + button -> clickButton(3) + ); + increaseLevelBtn = new Button( + sx + 91, sy + 97, 78, 20, + new TextComponent("Increase"), + button -> clickButton(4) + ); + + switchUnbreakableBtn = new Button( + sx + 7, sy + 123, 162, 20, + new TextComponent(""), + button -> clickButton(5) + ); + + addRenderableWidget(enchantBtn); + addRenderableWidget(prevBtn); + addRenderableWidget(nextBtn); + addRenderableWidget(decreaseLevelBtn); + addRenderableWidget(increaseLevelBtn); + addRenderableWidget(switchUnbreakableBtn); + addRenderableOnly(new Label( + new TextComponent("Selected Enchantment:"), + sx + 7, sy + 41, 0xFFFFFF, false + )); + addRenderableOnly(currentEnchantmentLabel); + } + + private void clickButton(int buttonId) { + assert Minecraft.getInstance().player != null; + menu.clickMenuButton(Minecraft.getInstance().player, buttonId); + } + + @Override + protected void renderBg(@NotNull PoseStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) { + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + RenderSystem.setShaderTexture(0, TEXTURE); + int x = (width - imageWidth) / 2; + int y = (height - imageHeight) / 2; + + this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight); + } + + @Override + protected void renderLabels(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY) { + this.font.draw(pPoseStack, this.title, (float) this.titleLabelX, (float) this.titleLabelY, 4210752); + } + + @Override + public void render(@NotNull PoseStack pPoseStack, int mouseX, int mouseY, float delta) { + renderBackground(pPoseStack); + super.render(pPoseStack, mouseX, mouseY, delta); + renderTooltip(pPoseStack, mouseX, mouseY); + + var enchantmentInstance = menu.getCurrentEnchantment(); + if (enchantmentInstance != null) { + var enchantment = enchantmentInstance.enchantment; + var level = enchantmentInstance.level; + MutableComponent description; + if (level == 0) { + description = new TranslatableComponent(enchantment.getDescriptionId()); + } else { + description = new TranslatableComponent(enchantment.getDescriptionId()); + description.withStyle(ChatFormatting.GREEN); + if (level != 1 || enchantment.getMaxLevel() != 1) { + description.append(" ").append(new TranslatableComponent("enchantment.level." + level)); + } + } + currentEnchantmentLabel.setText(description); + } else { + currentEnchantmentLabel.setText(new TextComponent("No enchantment selected")); + } + + var enchantmentRequirements = menu.getEnchantmentRequirements(); + + if (Minecraft.getInstance().player != null) { + enchantBtn.active = enchantmentInstance != null && menu.requirementsMet(Minecraft.getInstance().player, enchantmentRequirements); + } else { + enchantBtn.active = false; + } + nextBtn.active = enchantmentInstance != null; + prevBtn.active = enchantmentInstance != null; + increaseLevelBtn.active = enchantmentInstance != null; + decreaseLevelBtn.active = enchantmentInstance != null; + switchUnbreakableBtn.active = enchantmentInstance != null; + + switchUnbreakableBtn.setMessage(new TextComponent(menu.unbreakable() ? "Make unbreakable" : "Make breakable")); + + if (enchantmentInstance != null && enchantBtn.isHoveredOrFocused()) { + renderTooltip( + pPoseStack, + new TextComponent("Requirements: ") + .append(String.valueOf(enchantmentRequirements.lapis())) + .append(new TextComponent(" lapis").withStyle(ChatFormatting.BLUE)) + .append(", ") + .append(String.valueOf(enchantmentRequirements.netherite())) + .append(new TextComponent(" netherite").withStyle(ChatFormatting.DARK_PURPLE)) + .append(", ") + .append(String.valueOf(enchantmentRequirements.levels())) + .append(new TextComponent(" levels").withStyle(ChatFormatting.YELLOW)), + mouseX, mouseY + ); + } + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/screen/ModMenuTypes.java b/src/main/java/xyz/nuark/enchantrium/screen/ModMenuTypes.java new file mode 100644 index 0000000..b585370 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/screen/ModMenuTypes.java @@ -0,0 +1,28 @@ +package xyz.nuark.enchantrium.screen; + +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraftforge.common.extensions.IForgeMenuType; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.network.IContainerFactory; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import xyz.nuark.enchantrium.Enchantrium; + +public class ModMenuTypes { + public static final DeferredRegister> MENUS = + DeferredRegister.create(ForgeRegistries.CONTAINERS, Enchantrium.MOD_ID); + + public static final RegistryObject> ENCHANTER_MENU = registerMenuType( + EnchanterMenu::new, "enchanter_menu" + ); + + private static RegistryObject> registerMenuType(IContainerFactory factory, String name) { + return MENUS.register(name, () -> IForgeMenuType.create(factory)); + } + + public static void register(IEventBus eventBus) { + MENUS.register(eventBus); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/screen/slot/FilteredSlot.java b/src/main/java/xyz/nuark/enchantrium/screen/slot/FilteredSlot.java new file mode 100644 index 0000000..9bd9628 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/screen/slot/FilteredSlot.java @@ -0,0 +1,22 @@ +package xyz.nuark.enchantrium.screen.slot; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.SlotItemHandler; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +public class FilteredSlot extends SlotItemHandler { + Predicate filter; + + public FilteredSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition, Predicate filter) { + super(itemHandler, index, xPosition, yPosition); + this.filter = filter; + } + + @Override + public boolean mayPlace(@NotNull ItemStack stack) { + return filter.test(stack); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/screen/widget/Label.java b/src/main/java/xyz/nuark/enchantrium/screen/widget/Label.java new file mode 100644 index 0000000..460c400 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/screen/widget/Label.java @@ -0,0 +1,43 @@ +package xyz.nuark.enchantrium.screen.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.components.Widget; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +@OnlyIn(Dist.CLIENT) +public class Label implements Widget { + private Component text; + private final int x; + private final int y; + private final int color; + private final boolean centered; + + public Label(Component p_120736_, int p_120737_, int p_120738_, int p_120739_, boolean centered) { + this.text = p_120736_.copy(); + this.x = p_120737_; + this.y = p_120738_; + this.color = p_120739_; + this.centered = centered; + } + + public void render(@NotNull PoseStack p_175036_, int p_175037_, int p_175038_, float p_175039_) { + if (centered) { + GuiComponent.drawCenteredString(p_175036_, Minecraft.getInstance().font, this.text, this.x, this.y, this.color); + } else { + GuiComponent.drawString(p_175036_, Minecraft.getInstance().font, this.text, this.x, this.y, this.color); + } + } + + public void setText(Component p_175041_) { + this.text = p_175041_; + } + + public Component getText() { + return this.text; + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/setup/ClientSetup.java b/src/main/java/xyz/nuark/enchantrium/setup/ClientSetup.java new file mode 100644 index 0000000..5d1e774 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/setup/ClientSetup.java @@ -0,0 +1,14 @@ +package xyz.nuark.enchantrium.setup; + +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import xyz.nuark.enchantrium.screen.EnchanterScreen; +import xyz.nuark.enchantrium.screen.ModMenuTypes; + +public class ClientSetup { + public static void init(final FMLClientSetupEvent event) { + event.enqueueWork(() -> { + MenuScreens.register(ModMenuTypes.ENCHANTER_MENU.get(), EnchanterScreen::new); + }); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/setup/ModSetup.java b/src/main/java/xyz/nuark/enchantrium/setup/ModSetup.java new file mode 100644 index 0000000..2f32705 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/setup/ModSetup.java @@ -0,0 +1,30 @@ +package xyz.nuark.enchantrium.setup; + +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import org.jetbrains.annotations.NotNull; +import xyz.nuark.enchantrium.Enchantrium; +import xyz.nuark.enchantrium.item.ModItems; +import xyz.nuark.enchantrium.network.Networking; + +@Mod.EventBusSubscriber(modid = Enchantrium.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class ModSetup { + public static final CreativeModeTab ITEM_GROUP = new CreativeModeTab(Enchantrium.MOD_ID) { + @Override + public @NotNull ItemStack makeIcon() { + return new ItemStack(ModItems.TEST_ITEM.get()); + } + }; + + public static void setup() { + IEventBus bus = MinecraftForge.EVENT_BUS; + } + + public static void init(FMLCommonSetupEvent event) { + Networking.register(); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/setup/Registration.java b/src/main/java/xyz/nuark/enchantrium/setup/Registration.java new file mode 100644 index 0000000..3b26df3 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/setup/Registration.java @@ -0,0 +1,16 @@ +package xyz.nuark.enchantrium.setup; + +import net.minecraftforge.eventbus.api.IEventBus; +import xyz.nuark.enchantrium.block.ModBlocks; +import xyz.nuark.enchantrium.block.entity.ModBlockEntities; +import xyz.nuark.enchantrium.item.ModItems; +import xyz.nuark.enchantrium.screen.ModMenuTypes; + +public class Registration { + public static void register(IEventBus eventBus) { + ModItems.register(eventBus); + ModBlocks.register(eventBus); + ModBlockEntities.register(eventBus); + ModMenuTypes.register(eventBus); + } +} diff --git a/src/main/java/xyz/nuark/enchantrium/util/EnchantmentUtil.java b/src/main/java/xyz/nuark/enchantrium/util/EnchantmentUtil.java new file mode 100644 index 0000000..55cda09 --- /dev/null +++ b/src/main/java/xyz/nuark/enchantrium/util/EnchantmentUtil.java @@ -0,0 +1,44 @@ +package xyz.nuark.enchantrium.util; + +import com.google.common.collect.Lists; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.List; + +public class EnchantmentUtil { + public static boolean canBeEnchanted(ItemStack stack) { + return stack.getItem().isEnchantable(stack); + } + + public static List getApplicableEnchantments(ItemStack itemStack) { + List list = Lists.newArrayList(); + + for (Enchantment enchantment : ForgeRegistries.ENCHANTMENTS) { + if (enchantment.canEnchant(itemStack) && !enchantment.isCurse()) { + list.add(new EnchantmentInstance(enchantment, 0)); + } + } + + return list; + } + + public static EnchantmentCost calculateEnchantmentPrice(List enchantments, boolean hasUnbreaking) { + if (enchantments.isEmpty()) { + return new EnchantmentCost(0, 0, 0); + } + int lapis = Math.min(20 + enchantments.size() * (hasUnbreaking ? 6 : 3), 64); + int netherite = Math.min(Math.max((hasUnbreaking ? 5 : -3) + enchantments.size() / 2, 0), 64); + int levels = enchantments.stream().reduce( + 0, + (acc, enchantment) -> acc + enchantment.level, + Integer::sum + ); + return new EnchantmentCost(levels, lapis, netherite); + } + + public record EnchantmentCost(int levels, int lapis, int netherite) { + } +} diff --git a/src/main/resources/assets/enchantrium/textures/block/enchanter_side.png b/src/main/resources/assets/enchantrium/textures/block/enchanter_side.png new file mode 100644 index 0000000..81fc0b3 Binary files /dev/null and b/src/main/resources/assets/enchantrium/textures/block/enchanter_side.png differ diff --git a/src/main/resources/assets/enchantrium/textures/block/enchanter_top.png b/src/main/resources/assets/enchantrium/textures/block/enchanter_top.png new file mode 100644 index 0000000..8efc9bf Binary files /dev/null and b/src/main/resources/assets/enchantrium/textures/block/enchanter_top.png differ diff --git a/src/main/resources/assets/enchantrium/textures/gui/enchanter_gui.png b/src/main/resources/assets/enchantrium/textures/gui/enchanter_gui.png new file mode 100644 index 0000000..f28dbdd Binary files /dev/null and b/src/main/resources/assets/enchantrium/textures/gui/enchanter_gui.png differ diff --git a/src/main/resources/assets/enchantrium/textures/item/test_item.png b/src/main/resources/assets/enchantrium/textures/item/test_item.png new file mode 100644 index 0000000..a6b5a2e Binary files /dev/null and b/src/main/resources/assets/enchantrium/textures/item/test_item.png differ