diff --git a/src/main/java/io/github/reoseah/magisterium/Magisterium.java b/src/main/java/io/github/reoseah/magisterium/Magisterium.java index 2e108e5..5bd6095 100644 --- a/src/main/java/io/github/reoseah/magisterium/Magisterium.java +++ b/src/main/java/io/github/reoseah/magisterium/Magisterium.java @@ -22,7 +22,6 @@ import net.fabricmc.fabric.api.loot.v3.LootTableSource; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.block.BlockState; import net.minecraft.block.LecternBlock; import net.minecraft.block.entity.LecternBlockEntity; import net.minecraft.entity.player.PlayerEntity; @@ -35,14 +34,12 @@ import net.minecraft.registry.*; import net.minecraft.screen.NamedScreenHandlerFactory; import net.minecraft.screen.ScreenHandler; -import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; import org.slf4j.Logger; @@ -77,7 +74,7 @@ public void onInitialize() { Registry.register(Registries.ITEM, "magisterium:bookmark", BookmarkItem.INSTANCE); Registry.register(Registries.DATA_COMPONENT_TYPE, "magisterium:current_page", SpellBookItem.CURRENT_PAGE); - Registry.register(Registries.DATA_COMPONENT_TYPE, "magisterium:page_data", SpellBookItem.PAGES); + Registry.register(Registries.DATA_COMPONENT_TYPE, "magisterium:contents", SpellBookItem.CONTENTS); Registry.register(Registries.DATA_COMPONENT_TYPE, "magisterium:unstable_charge", SpellBookItem.UNSTABLE_CHARGE); var group = FabricItemGroup.builder() // diff --git a/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java b/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java index 0dee7cc..a6aa766 100644 --- a/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java +++ b/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java @@ -4,6 +4,7 @@ import io.github.reoseah.magisterium.block.GlyphBlock; import io.github.reoseah.magisterium.block.IllusoryWallBlockEntity; import io.github.reoseah.magisterium.block.IllusoryWallBlockEntityRenderer; +import io.github.reoseah.magisterium.item.SpellBookItem; import io.github.reoseah.magisterium.screen.ArcaneTableScreen; import io.github.reoseah.magisterium.screen.ArcaneTableScreenHandler; import io.github.reoseah.magisterium.screen.SpellBookScreen; @@ -11,11 +12,15 @@ import io.github.reoseah.magisterium.spellbook.SpellDataLoader; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.impl.resource.loader.ResourceManagerHelperImpl; import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.item.ModelPredicateProviderRegistry; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.block.entity.BlockEntityRendererFactories; +import net.minecraft.client.util.ModelIdentifier; import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; public class MagisteriumClient implements ClientModInitializer { @Override @@ -27,6 +32,11 @@ public void onInitializeClient() { BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ArcaneTableBlock.INSTANCE, GlyphBlock.INSTANCE); + ModelLoadingPlugin.register(ctx -> ctx.addModels(Identifier.of("magisterium", "item/spell_book_in_hand"))); + + ModelPredicateProviderRegistry.register(SpellBookItem.INSTANCE, Identifier.of("magisterium:is_in_hand"), // + (stack, world, entity, seed) -> entity != null && entity.getActiveItem().equals(stack) ? 1.0F : 0.0F); + HandledScreens.register(SpellBookScreenHandler.TYPE, SpellBookScreen::new); HandledScreens.register(ArcaneTableScreenHandler.TYPE, ArcaneTableScreen::new); diff --git a/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java b/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java index fa9f2b1..67ad951 100644 --- a/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java +++ b/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java @@ -30,7 +30,7 @@ public class SpellBookItem extends Item { .codec(Codecs.NONNEGATIVE_INT) // .packetCodec(PacketCodecs.VAR_INT) // .build(); - public static final ComponentType> PAGES = ComponentType.>builder() // + public static final ComponentType> CONTENTS = ComponentType.>builder() // .codec(ItemStack.OPTIONAL_CODEC.listOf()) // .packetCodec(ItemStack.OPTIONAL_PACKET_CODEC.collect(PacketCodecs.toList())) // .build(); @@ -47,7 +47,7 @@ protected SpellBookItem(Settings settings) { public static ItemStack createTestBook() { ItemStack book = new ItemStack(INSTANCE); - book.set(PAGES, Util.make(DefaultedList.ofSize(18, ItemStack.EMPTY), list -> { + book.set(CONTENTS, Util.make(DefaultedList.ofSize(18, ItemStack.EMPTY), list -> { list.set(0, BookmarkItem.INSTANCE.getDefaultStack()); list.set(1, SpellPageItem.AWAKEN_THE_FLAME.getDefaultStack()); list.set(2, SpellPageItem.QUENCH_THE_FLAME.getDefaultStack()); @@ -65,7 +65,7 @@ public static ItemStack createTestBook() { public TypedActionResult use(World world, PlayerEntity player, Hand hand) { var book = player.getStackInHand(hand); - if (!book.contains(PAGES)) { + if (!book.contains(CONTENTS)) { return TypedActionResult.fail(book); } @@ -88,7 +88,7 @@ public Text getDisplayName() { @Override public void appendTooltip(ItemStack stack, TooltipContext context, List tooltip, TooltipType type) { super.appendTooltip(stack, context, tooltip, type); - var pages = stack.get(PAGES); + var pages = stack.get(CONTENTS); if (pages != null && !pages.isEmpty()) { var nonEmptyCount = pages.stream().filter(page -> !page.isEmpty()).count(); tooltip.add(Text.translatable("item.magisterium.spell_book.pages", nonEmptyCount).formatted(Formatting.GRAY)); diff --git a/src/main/java/io/github/reoseah/magisterium/mixin/client/BuiltinItemModelRendererMixin.java b/src/main/java/io/github/reoseah/magisterium/mixin/client/BuiltinItemModelRendererMixin.java new file mode 100644 index 0000000..6387b75 --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/mixin/client/BuiltinItemModelRendererMixin.java @@ -0,0 +1,49 @@ +package io.github.reoseah.magisterium.mixin.client; + +import io.github.reoseah.magisterium.item.SpellBookItem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.model.BookModel; +import net.minecraft.client.render.entity.model.EntityModelLayers; +import net.minecraft.client.render.item.BuiltinModelItemRenderer; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.json.ModelTransformationMode; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BuiltinModelItemRenderer.class) +public class BuiltinItemModelRendererMixin { + @Unique + private static final Identifier TEXTURE = Identifier.of("magisterium", "textures/entity/spell_book.png"); + + @Unique + private BookModel bookModel; + + @Inject(at = @At("HEAD"), method = "reload") + public void reload(ResourceManager manager, CallbackInfo ci) { + this.bookModel = new BookModel(MinecraftClient.getInstance().getEntityModelLoader().getModelPart(EntityModelLayers.BOOK)); + } + + @Inject(at = @At("HEAD"), method = "render", cancellable = true) + public void render(ItemStack stack, ModelTransformationMode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, CallbackInfo ci) { + Item item = stack.getItem(); + if (item == SpellBookItem.INSTANCE) { + matrices.push(); + matrices.scale(1, -1, -1); + VertexConsumer vertexConsumer = ItemRenderer.getDirectItemGlintConsumer(vertexConsumers, this.bookModel.getLayer(TEXTURE), false, false); + this.bookModel.setPageAngles(0, 0.1F, 0.9F, 1.2F); + this.bookModel.render(matrices, vertexConsumer, light, overlay, 0xFFFFFF); + matrices.pop(); + ci.cancel(); + } + } +} diff --git a/src/main/java/io/github/reoseah/magisterium/mixin/client/ItemRendererMixin.java b/src/main/java/io/github/reoseah/magisterium/mixin/client/ItemRendererMixin.java new file mode 100644 index 0000000..d279bb7 --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/mixin/client/ItemRendererMixin.java @@ -0,0 +1,85 @@ +package io.github.reoseah.magisterium.mixin.client; + +import io.github.reoseah.magisterium.item.SpellBookItem; +import net.minecraft.client.render.*; +import net.minecraft.client.render.item.BuiltinModelItemRenderer; +import net.minecraft.client.render.item.ItemModels; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformationMode; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Objects; + +@Mixin(ItemRenderer.class) +public abstract class ItemRendererMixin { + @Unique + private static final ModelIdentifier SPELL_BOOK = ModelIdentifier.ofInventoryVariant(Identifier.of("magisterium", "spell_book")); + @Unique + private static final Identifier SPELL_BOOK_IN_HAND = Identifier.of("magisterium", "item/spell_book_in_hand"); + + @Shadow + private @Final ItemModels models; + @Shadow + private @Final BuiltinModelItemRenderer builtinModelItemRenderer; + + @Shadow + protected abstract void renderBakedItemModel(BakedModel model, ItemStack stack, int light, int overlay, MatrixStack matrices, VertexConsumer vertices); + + @Inject(at = @At("HEAD"), method = "getModel", cancellable = true) + public void setHemonomiconModel(ItemStack stack, @Nullable World world, @Nullable LivingEntity entity, int seed, CallbackInfoReturnable ci) { + Item item = stack.getItem(); + if (item == SpellBookItem.INSTANCE) { + BakedModel model = this.models.getModelManager().getModel(SPELL_BOOK_IN_HAND); + ClientWorld clientWorld = world instanceof ClientWorld ? (ClientWorld) world : null; + model = model.getOverrides().apply(model, stack, clientWorld, entity, seed); + ci.setReturnValue(model == null ? this.models.getModelManager().getMissingModel() : model); + } + } + + @Inject(at = @At("HEAD"), method = "renderItem", cancellable = true) + public void renderHemonomicon(ItemStack stack, ModelTransformationMode mode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { + if (!stack.isEmpty() && stack.getItem() == SpellBookItem.INSTANCE) { + matrices.push(); + boolean gui = mode == ModelTransformationMode.GUI; + boolean notInHand = gui || mode == ModelTransformationMode.GROUND || mode == ModelTransformationMode.FIXED; + if (notInHand) { + model = this.models.getModelManager().getModel(SPELL_BOOK); + } + model.getTransformation().getTransformation(mode).apply(leftHanded, matrices); + matrices.translate(-0.5D, -0.5D, -0.5D); + if (model.isBuiltin() || !notInHand) { + this.builtinModelItemRenderer.render(stack, mode, matrices, vertexConsumers, light, overlay); + } else { + RenderLayer itemLayer = RenderLayers.getItemLayer(stack, true); + RenderLayer layer; + if (gui && Objects.equals(itemLayer, TexturedRenderLayers.getEntityTranslucentCull())) { + layer = TexturedRenderLayers.getEntityTranslucentCull(); + } else { + layer = itemLayer; + } + + VertexConsumer vertexConsumer = ItemRenderer.getDirectItemGlintConsumer(vertexConsumers, layer, true, stack.hasGlint()); + this.renderBakedItemModel(model, stack, light, overlay, matrices, vertexConsumer); + } + matrices.pop(); + ci.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/reoseah/magisterium/network/UseBookmarkPayload.java b/src/main/java/io/github/reoseah/magisterium/network/UseBookmarkPayload.java index 82a5294..7f99a51 100644 --- a/src/main/java/io/github/reoseah/magisterium/network/UseBookmarkPayload.java +++ b/src/main/java/io/github/reoseah/magisterium/network/UseBookmarkPayload.java @@ -9,7 +9,7 @@ // but first two buttons ids are taken by page navigation // and I find it awkward to have to "encode" page into a distinct button id public record UseBookmarkPayload(int page) implements CustomPayload { - public static final CustomPayload.Id ID = new CustomPayload.Id<>(Identifier.of("hematurgy:hemonomicon/use_bookmark")); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(Identifier.of("magisterium:use_bookmark")); public static final PacketCodec CODEC = CustomPayload.codecOf(UseBookmarkPayload::write, UseBookmarkPayload::new); public UseBookmarkPayload(PacketByteBuf buf) { diff --git a/src/main/java/io/github/reoseah/magisterium/screen/ArcaneTableScreenHandler.java b/src/main/java/io/github/reoseah/magisterium/screen/ArcaneTableScreenHandler.java index c085945..6696d9d 100644 --- a/src/main/java/io/github/reoseah/magisterium/screen/ArcaneTableScreenHandler.java +++ b/src/main/java/io/github/reoseah/magisterium/screen/ArcaneTableScreenHandler.java @@ -51,12 +51,12 @@ public boolean canInsert(ItemStack stack) { this.addSlot(new Slot(this.bookContentsInventory, column + row * 6, 81 + column * 18, 18 + row * 18) { @Override public boolean canTakeItems(PlayerEntity playerEntity) { - return bookInventory.getStack(0).contains(SpellBookItem.PAGES); + return bookInventory.getStack(0).contains(SpellBookItem.CONTENTS); } @Override public boolean canInsert(ItemStack stack) { - return bookInventory.getStack(0).contains(SpellBookItem.PAGES) // + return bookInventory.getStack(0).contains(SpellBookItem.CONTENTS) // && stack.isIn(MagisteriumItemTags.SPELL_BOOK_COMPONENTS); } }); @@ -97,7 +97,7 @@ public ItemStack quickMove(PlayerEntity player, int index) { if (!this.insertItem(stack, 0, 1, false)) { return ItemStack.EMPTY; } - } else if (stack.isIn(MagisteriumItemTags.SPELL_BOOK_COMPONENTS) && bookInventory.getStack(0).contains(SpellBookItem.PAGES)) { + } else if (stack.isIn(MagisteriumItemTags.SPELL_BOOK_COMPONENTS) && bookInventory.getStack(0).contains(SpellBookItem.CONTENTS)) { if (!this.insertItem(stack, 1, 1 + 18, false)) { return ItemStack.EMPTY; } @@ -151,7 +151,7 @@ public BookContentsInventory(SimpleInventory bookInventory) { if (book != this.book) { this.clearWithoutNotifyingListeners(); if (book.isOf(SpellBookItem.INSTANCE)) { - var bookPages = book.get(SpellBookItem.PAGES); + var bookPages = book.get(SpellBookItem.CONTENTS); if (bookPages != null) { for (int i = 0; i < bookPages.size(); i++) { this.heldStacks.set(i, bookPages.get(i)); @@ -165,7 +165,7 @@ public BookContentsInventory(SimpleInventory bookInventory) { var book = this.bookInventory.getStack(0); if (book.isOf(SpellBookItem.INSTANCE)) { book.set(SpellBookItem.CURRENT_PAGE, 0); - book.set(SpellBookItem.PAGES, new ArrayList<>(this.getHeldStacks())); + book.set(SpellBookItem.CONTENTS, new ArrayList<>(this.getHeldStacks())); } }); } diff --git a/src/main/java/io/github/reoseah/magisterium/screen/SpellBookScreen.java b/src/main/java/io/github/reoseah/magisterium/screen/SpellBookScreen.java index d85d3eb..2705d18 100644 --- a/src/main/java/io/github/reoseah/magisterium/screen/SpellBookScreen.java +++ b/src/main/java/io/github/reoseah/magisterium/screen/SpellBookScreen.java @@ -106,7 +106,7 @@ protected void init() { .formatted(Formatting.ITALIC).styled(style -> style.withColor(0xc4b090)); private void buildPages() { - var pages = this.handler.getSpellBook().getOrDefault(SpellBookItem.PAGES, DefaultedList.ofSize(18, ItemStack.EMPTY)); + var pages = this.handler.getSpellBook().getOrDefault(SpellBookItem.CONTENTS, DefaultedList.ofSize(18, ItemStack.EMPTY)); var builder = new BookLayout.Builder(this.properties); for (ItemStack stack : pages) { diff --git a/src/main/resources/assets/magisterium/icon.png b/src/main/resources/assets/magisterium/icon.png index 047b91f..faedee7 100644 Binary files a/src/main/resources/assets/magisterium/icon.png and b/src/main/resources/assets/magisterium/icon.png differ diff --git a/src/main/resources/assets/magisterium/models/item/spell_book.json b/src/main/resources/assets/magisterium/models/item/spell_book.json index 2494f8b..38e1b83 100644 --- a/src/main/resources/assets/magisterium/models/item/spell_book.json +++ b/src/main/resources/assets/magisterium/models/item/spell_book.json @@ -2,5 +2,13 @@ "parent": "minecraft:item/generated", "textures": { "layer0": "magisterium:item/spell_book" - } + }, + "overrides": [ + { + "predicate": { + "magisterium:is_in_hand": 1 + }, + "model": "magisterium:item/spell_book_in_hand" + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/models/item/spell_book_in_hand.json b/src/main/resources/assets/magisterium/models/item/spell_book_in_hand.json new file mode 100644 index 0000000..ece6207 --- /dev/null +++ b/src/main/resources/assets/magisterium/models/item/spell_book_in_hand.json @@ -0,0 +1,44 @@ +{ + "parent": "builtin/entity", + "gui_light": "front", + "textures": { + "particle": "magisterium:item/spell_book" + }, + "display": { + "thirdperson_righthand": { + "rotation": [0, -120, 0], + "translation": [-12, 12, 3], + "scale": [1, 1, 1] + }, + "thirdperson_lefthand": { + "rotation": [0, 60, 0], + "translation": [3, 12, 12], + "scale": [1, 1, 1] + }, + "firstperson_righthand": { + "rotation": [0, -90, 25], + "translation": [-3, 12, 1], + "scale": [1, 1, 1] + }, + "firstperson_lefthand": { + "rotation": [0, 90, -25], + "translation": [13, 12, 1], + "scale": [1, 1, 1] + }, + "gui": { + "rotation": [15, -25, -5], + "translation": [2, 3, 0], + "scale": [0.65, 0.65, 0.65] + }, + "fixed": { + "rotation": [0, 180, 0], + "translation": [-2, 4, -5], + "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "rotation": [0, 0, 0], + "translation": [4, 4, 2], + "scale": [0.25, 0.25, 0.25] + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/magisterium/loot_table/chests/parts/common_loot.json b/src/main/resources/data/magisterium/loot_table/chests/parts/common_loot.json index 8060adf..38791fb 100644 --- a/src/main/resources/data/magisterium/loot_table/chests/parts/common_loot.json +++ b/src/main/resources/data/magisterium/loot_table/chests/parts/common_loot.json @@ -6,12 +6,12 @@ { "type": "minecraft:item", "weight": 10, - "name": "magisterium:awaken_the_fire_page" + "name": "magisterium:awaken_the_flame_page" }, { "type": "minecraft:item", "weight": 10, - "name": "magisterium:quench_the_fire_page" + "name": "magisterium:quench_the_flame_page" }, { "type": "minecraft:item", diff --git a/src/main/resources/data/magisterium/loot_table/chests/parts/rare_loot.json b/src/main/resources/data/magisterium/loot_table/chests/parts/rare_loot.json index 50f71da..af21d52 100644 --- a/src/main/resources/data/magisterium/loot_table/chests/parts/rare_loot.json +++ b/src/main/resources/data/magisterium/loot_table/chests/parts/rare_loot.json @@ -11,7 +11,7 @@ { "function": "set_components", "components": { - "magisterium:pages": [ + "magisterium:contents": [ { "id": "magisterium:awaken_the_flame_page", "count": 1 diff --git a/src/main/resources/magisterium.client.mixins.json b/src/main/resources/magisterium.client.mixins.json index c75872d..a372060 100644 --- a/src/main/resources/magisterium.client.mixins.json +++ b/src/main/resources/magisterium.client.mixins.json @@ -3,6 +3,8 @@ "package": "io.github.reoseah.magisterium.mixin.client", "compatibilityLevel": "JAVA_21", "client": [ + "BuiltinItemModelRendererMixin", + "ItemRendererMixin", "LecternBlockEntityRendererMixin" ], "injectors": {