diff --git a/src/main/java/dev/hephaestus/glowcase/Glowcase.java b/src/main/java/dev/hephaestus/glowcase/Glowcase.java index 8f32138..b9c7057 100644 --- a/src/main/java/dev/hephaestus/glowcase/Glowcase.java +++ b/src/main/java/dev/hephaestus/glowcase/Glowcase.java @@ -4,9 +4,13 @@ import com.google.common.base.Suppliers; import dev.hephaestus.glowcase.block.HyperlinkBlock; import dev.hephaestus.glowcase.block.ItemDisplayBlock; +import dev.hephaestus.glowcase.block.PopupBlock; +import dev.hephaestus.glowcase.block.SpriteBlock; import dev.hephaestus.glowcase.block.TextBlock; import dev.hephaestus.glowcase.block.entity.HyperlinkBlockEntity; import dev.hephaestus.glowcase.block.entity.ItemDisplayBlockEntity; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; import dev.hephaestus.glowcase.compat.PolydexCompatibility; import dev.hephaestus.glowcase.item.LockItem; @@ -47,6 +51,14 @@ public class Glowcase implements ModInitializer { public static final Supplier TEXT_BLOCK_ITEM = registerItem("text_block", () -> new BlockItem(TEXT_BLOCK.get(), new Item.Settings())); public static final Supplier> TEXT_BLOCK_ENTITY = registerBlockEntity("text_block", () -> BlockEntityType.Builder.create(TextBlockEntity::new, TEXT_BLOCK.get()).build(null)); + public static final Supplier POPUP_BLOCK = registerBlock("popup_block", PopupBlock::new); + public static final Supplier POPUP_BLOCK_ITEM = registerItem("popup_block", () -> new BlockItem(POPUP_BLOCK.get(), new Item.Settings())); + public static final Supplier> POPUP_BLOCK_ENTITY = registerBlockEntity("popup_block", () -> BlockEntityType.Builder.create(PopupBlockEntity::new, POPUP_BLOCK.get()).build(null)); + + public static final Supplier SPRITE_BLOCK = registerBlock("sprite_block", SpriteBlock::new); + public static final Supplier SPRITE_BLOCK_ITEM = registerItem("sprite_block", () -> new BlockItem(SPRITE_BLOCK.get(), new Item.Settings())); + public static final Supplier> SPRITE_BLOCK_ENTITY = registerBlockEntity("sprite_block", () -> BlockEntityType.Builder.create(SpriteBlockEntity::new, SPRITE_BLOCK.get()).build(null)); + public static final Supplier LOCK_ITEM = registerItem("lock", () -> new LockItem(new Item.Settings())); public static final Supplier ITEM_GROUP = registerItemGroup("items", () -> FabricItemGroup.builder() @@ -56,6 +68,8 @@ public class Glowcase implements ModInitializer { entries.add(HYPERLINK_BLOCK_ITEM.get()); entries.add(ITEM_DISPLAY_BLOCK_ITEM.get()); entries.add(TEXT_BLOCK_ITEM.get()); + entries.add(POPUP_BLOCK_ITEM.get()); + entries.add(SPRITE_BLOCK_ITEM.get()); entries.add(LOCK_ITEM.get()); }) .build() diff --git a/src/main/java/dev/hephaestus/glowcase/GlowcaseCommonProxy.java b/src/main/java/dev/hephaestus/glowcase/GlowcaseCommonProxy.java index 65ee6c0..13e4ccd 100644 --- a/src/main/java/dev/hephaestus/glowcase/GlowcaseCommonProxy.java +++ b/src/main/java/dev/hephaestus/glowcase/GlowcaseCommonProxy.java @@ -18,4 +18,16 @@ public void openItemDisplayBlockEditScreen(BlockPos pos) { public void openTextBlockEditScreen(BlockPos pos) { //No-op } + + public void openPopupBlockEditScreen(BlockPos pos) { + //No-op + } + + public void openPopupBlockViewScreen(BlockPos pos) { + //No-op + } + + public void openSpriteBlockEditScreen(BlockPos pos) { + //No-op + } } diff --git a/src/main/java/dev/hephaestus/glowcase/GlowcaseNetworking.java b/src/main/java/dev/hephaestus/glowcase/GlowcaseNetworking.java index 8b932a4..fc73803 100644 --- a/src/main/java/dev/hephaestus/glowcase/GlowcaseNetworking.java +++ b/src/main/java/dev/hephaestus/glowcase/GlowcaseNetworking.java @@ -3,6 +3,8 @@ import dev.hephaestus.glowcase.packet.C2SEditHyperlinkBlock; import dev.hephaestus.glowcase.packet.C2SEditItemDisplayBlock; import dev.hephaestus.glowcase.packet.C2SEditTextBlock; +import dev.hephaestus.glowcase.packet.C2SEditPopupBlock; +import dev.hephaestus.glowcase.packet.C2SEditSpriteBlock; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; @@ -11,9 +13,13 @@ public static void init() { PayloadTypeRegistry.playC2S().register(C2SEditHyperlinkBlock.ID, C2SEditHyperlinkBlock.PACKET_CODEC); PayloadTypeRegistry.playC2S().register(C2SEditItemDisplayBlock.ID, C2SEditItemDisplayBlock.PACKET_CODEC); PayloadTypeRegistry.playC2S().register(C2SEditTextBlock.ID, C2SEditTextBlock.PACKET_CODEC); + PayloadTypeRegistry.playC2S().register(C2SEditPopupBlock.ID, C2SEditPopupBlock.PACKET_CODEC); + PayloadTypeRegistry.playC2S().register(C2SEditSpriteBlock.ID, C2SEditSpriteBlock.PACKET_CODEC); ServerPlayNetworking.registerGlobalReceiver(C2SEditHyperlinkBlock.ID, C2SEditHyperlinkBlock::receive); ServerPlayNetworking.registerGlobalReceiver(C2SEditItemDisplayBlock.ID, C2SEditItemDisplayBlock::receive); ServerPlayNetworking.registerGlobalReceiver(C2SEditTextBlock.ID, C2SEditTextBlock::receive); + ServerPlayNetworking.registerGlobalReceiver(C2SEditPopupBlock.ID, C2SEditPopupBlock::receive); + ServerPlayNetworking.registerGlobalReceiver(C2SEditSpriteBlock.ID, C2SEditSpriteBlock::receive); } } diff --git a/src/main/java/dev/hephaestus/glowcase/block/PopupBlock.java b/src/main/java/dev/hephaestus/glowcase/block/PopupBlock.java new file mode 100644 index 0000000..122084e --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/block/PopupBlock.java @@ -0,0 +1,85 @@ +package dev.hephaestus.glowcase.block; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.tooltip.TooltipType; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class PopupBlock extends GlowcaseBlock implements BlockEntityProvider { + private static final VoxelShape OUTLINE = VoxelShapes.cuboid(0.25, 0.25, 0.25, 0.75, 0.75, 0.75); + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return OUTLINE; + } + + @Nullable + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new PopupBlockEntity(pos, state); + } + + @Override + public void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + if (world.isClient && placer instanceof PlayerEntity player && canEditGlowcase(player, pos)) { + //load any ctrl-picked NBT clientside + NbtComponent blockEntityTag = stack.get(DataComponentTypes.BLOCK_ENTITY_DATA); + if (blockEntityTag != null && world.getBlockEntity(pos) instanceof PopupBlockEntity be) { + blockEntityTag.applyToBlockEntity(be, world.getRegistryManager()); + } + + Glowcase.proxy.openPopupBlockEditScreen(pos); + } + } + + @Override + protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { + if (!(world.getBlockEntity(pos) instanceof PopupBlockEntity be)) return ActionResult.CONSUME; + if (world.isClient) { + Glowcase.proxy.openPopupBlockViewScreen(pos); + } + return ActionResult.SUCCESS; + } + + @Override + protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + if (!(world.getBlockEntity(pos) instanceof PopupBlockEntity)) return ItemActionResult.CONSUME; + if (player.getStackInHand(hand).isIn(Glowcase.ITEM_TAG) && canEditGlowcase(player, pos)) { + if (world.isClient) { + Glowcase.proxy.openPopupBlockEditScreen(pos); + } + return ItemActionResult.SUCCESS; + } + return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } + + @Override + public void appendTooltip(ItemStack itemStack, Item.TooltipContext context, List tooltip, TooltipType options) { + tooltip.add(Text.translatable("block.glowcase.popup_block.tooltip.0").formatted(Formatting.GRAY)); + tooltip.add(Text.translatable("block.glowcase.generic.tooltip").formatted(Formatting.DARK_GRAY)); + tooltip.add(Text.translatable("block.glowcase.popup_block.tooltip.1").formatted(Formatting.DARK_GRAY)); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/block/SpriteBlock.java b/src/main/java/dev/hephaestus/glowcase/block/SpriteBlock.java new file mode 100644 index 0000000..5a80591 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/block/SpriteBlock.java @@ -0,0 +1,84 @@ +package dev.hephaestus.glowcase.block; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.item.tooltip.TooltipType; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.Properties; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class SpriteBlock extends GlowcaseBlock implements BlockEntityProvider { + public SpriteBlock() { + super(); + this.setDefaultState(this.getDefaultState().with(Properties.ROTATION, 0)); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder); + builder.add(Properties.ROTATION); + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return this.getDefaultState().with(Properties.ROTATION, MathHelper.floor((double) ((180.0F + ctx.getPlayerYaw()) * 16.0F / 360.0F) + 0.5D) & 15); + } + + @Nullable + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new SpriteBlockEntity(pos, state); + } + + @Override + public void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + if (world.isClient && placer instanceof PlayerEntity player && canEditGlowcase(player, pos)) { + //load any ctrl-picked NBT clientside + NbtComponent blockEntityTag = stack.get(DataComponentTypes.BLOCK_ENTITY_DATA); + if (blockEntityTag != null && world.getBlockEntity(pos) instanceof SpriteBlockEntity be) { + blockEntityTag.applyToBlockEntity(be, world.getRegistryManager()); + } + + Glowcase.proxy.openSpriteBlockEditScreen(pos); + } + } + + @Override + protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + if (!(world.getBlockEntity(pos) instanceof SpriteBlockEntity be)) return ItemActionResult.CONSUME; + + if (world.isClient && player.getStackInHand(hand).isIn(Glowcase.ITEM_TAG) && canEditGlowcase(player, pos)) { + Glowcase.proxy.openSpriteBlockEditScreen(pos); + } + + return ItemActionResult.SUCCESS; + } + + @Override + public void appendTooltip(ItemStack itemStack, Item.TooltipContext context, List tooltip, TooltipType options) { + tooltip.add(Text.translatable("block.glowcase.sprite_block.tooltip.0").formatted(Formatting.GRAY)); + tooltip.add(Text.translatable("block.glowcase.generic.tooltip").formatted(Formatting.DARK_GRAY)); + tooltip.add(Text.translatable("block.glowcase.sprite_block.tooltip.1").formatted(Formatting.DARK_GRAY)); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/block/entity/PopupBlockEntity.java b/src/main/java/dev/hephaestus/glowcase/block/entity/PopupBlockEntity.java new file mode 100644 index 0000000..c33d48c --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/block/entity/PopupBlockEntity.java @@ -0,0 +1,137 @@ +package dev.hephaestus.glowcase.block.entity; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.client.render.block.entity.BakedBlockEntityRenderer; +import eu.pb4.placeholders.api.ParserContext; +import eu.pb4.placeholders.api.parsers.NodeParser; +import eu.pb4.placeholders.api.parsers.TagParser; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class PopupBlockEntity extends BlockEntity { + public static final NodeParser PARSER = TagParser.DEFAULT; + public String title = ""; + public List lines = new ArrayList<>(); + public TextBlockEntity.TextAlignment textAlignment = TextBlockEntity.TextAlignment.CENTER; + public int color = 0xFFFFFF; + public boolean renderDirty = true; + + public PopupBlockEntity(BlockPos pos, BlockState state) { + super(Glowcase.POPUP_BLOCK_ENTITY.get(), pos, state); + lines.add(Text.empty()); + } + + @Override + protected void writeNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(tag, registryLookup); + + tag.putString("title", this.title); + tag.putInt("color", this.color); + + tag.putString("text_alignment", this.textAlignment.name()); + + NbtList lines = tag.getList("lines", 8); + for (var text : this.lines) { + lines.add(NbtString.of(Text.Serialization.toJsonString(text, registryLookup))); + } + + tag.put("lines", lines); + } + + @Override + protected void readNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { + super.readNbt(tag, registryLookup); + + this.title = tag.getString("title"); + this.lines = new ArrayList<>(); + this.color = tag.getInt("color"); + + this.textAlignment = TextBlockEntity.TextAlignment.valueOf(tag.getString("text_alignment")); + + NbtList lines = tag.getList("lines", 8); + + for (NbtElement line : lines) { + if (line.getType() == NbtElement.END_TYPE) break; + this.lines.add(Text.Serialization.fromJson(line.asString(), registryLookup)); + } + + this.renderDirty = true; + } + + public String getRawLine(int i) { + var line = this.lines.get(i); + + if (line.getStyle() == null) { + return line.getString(); + } + + var insert = line.getStyle().getInsertion(); + + if (insert == null) { + return line.getString(); + } + return insert; + } + + public void addRawLine(int i, String string) { + var parsed = PARSER.parseText(string, ParserContext.of()); + + if (parsed.getString().equals(string)) { + this.lines.add(i, Text.literal(string)); + } else { + this.lines.add(i, Text.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string))); + } + } + + public void setRawLine(int i, String string) { + var parsed = PARSER.parseText(string, ParserContext.of()); + + if (parsed.getString().equals(string)) { + this.lines.set(i, Text.literal(string)); + } else { + this.lines.set(i, Text.empty().append(parsed).setStyle(Style.EMPTY.withInsertion(string))); + } + } + + @SuppressWarnings({"MethodCallSideOnly", "VariableUseSideOnly"}) + @Override + public void markRemoved() { + if (world != null && world.isClient) { + BakedBlockEntityRenderer.Manager.markForRebuild(getPos()); + } + super.markRemoved(); + } + + // standard blockentity boilerplate + + public void dispatch() { + if (world instanceof ServerWorld sworld) sworld.getChunkManager().markForUpdate(pos); + } + + @Override + public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { + return createNbt(registryLookup); + } + + @Nullable + @Override + public Packet toUpdatePacket() { + return BlockEntityUpdateS2CPacket.create(this); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/block/entity/SpriteBlockEntity.java b/src/main/java/dev/hephaestus/glowcase/block/entity/SpriteBlockEntity.java new file mode 100644 index 0000000..9e171ab --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/block/entity/SpriteBlockEntity.java @@ -0,0 +1,77 @@ +package dev.hephaestus.glowcase.block.entity; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.client.render.block.entity.BakedBlockEntityRenderer; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import org.jetbrains.annotations.Nullable; + +public class SpriteBlockEntity extends BlockEntity { + public String sprite = "arrow"; + public int rotation = 0; + public TextBlockEntity.ZOffset zOffset = TextBlockEntity.ZOffset.CENTER; + public int color = 0xFFFFFF; + + public SpriteBlockEntity(BlockPos pos, BlockState state) { + super(Glowcase.SPRITE_BLOCK_ENTITY.get(), pos, state); + } + + public void setSprite(String newSprite) { + sprite = newSprite; + markDirty(); + dispatch(); + } + + @Override + public void writeNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(tag, registryLookup); + + tag.putString("sprite", this.sprite); + tag.putInt("rotation", this.rotation); + tag.putString("z_offset", this.zOffset.name()); + tag.putInt("color", this.color); + } + + @Override + public void readNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) { + super.readNbt(tag, registryLookup); + + this.sprite = tag.getString("sprite"); + this.rotation = tag.getInt("rotation"); + this.zOffset = TextBlockEntity.ZOffset.valueOf(tag.getString("z_offset")); + this.color = tag.getInt("color"); + } + + @SuppressWarnings({"MethodCallSideOnly", "VariableUseSideOnly"}) + @Override + public void markRemoved() { + if (world != null && world.isClient) { + BakedBlockEntityRenderer.Manager.markForRebuild(getPos()); + } + super.markRemoved(); + } + + // standard blockentity boilerplate + + public void dispatch() { + if (world instanceof ServerWorld sworld) sworld.getChunkManager().markForUpdate(pos); + } + + @Override + public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { + return createNbt(registryLookup); + } + + @Nullable + @Override + public Packet toUpdatePacket() { + return BlockEntityUpdateS2CPacket.create(this); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClient.java b/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClient.java index 02b4a8e..d65470a 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClient.java +++ b/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClient.java @@ -5,6 +5,8 @@ import dev.hephaestus.glowcase.client.render.block.entity.HyperlinkBlockEntityRenderer; import dev.hephaestus.glowcase.client.render.block.entity.ItemDisplayBlockEntityRenderer; import dev.hephaestus.glowcase.client.render.block.entity.TextBlockEntityRenderer; +import dev.hephaestus.glowcase.client.render.block.entity.PopupBlockEntityRenderer; +import dev.hephaestus.glowcase.client.render.block.entity.SpriteBlockEntityRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.InvalidateRenderStateCallback; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; @@ -18,6 +20,8 @@ public void onInitializeClient() { BlockEntityRendererFactories.register(Glowcase.TEXT_BLOCK_ENTITY.get(), TextBlockEntityRenderer::new); BlockEntityRendererFactories.register(Glowcase.HYPERLINK_BLOCK_ENTITY.get(), HyperlinkBlockEntityRenderer::new); BlockEntityRendererFactories.register(Glowcase.ITEM_DISPLAY_BLOCK_ENTITY.get(), ItemDisplayBlockEntityRenderer::new); + BlockEntityRendererFactories.register(Glowcase.POPUP_BLOCK_ENTITY.get(), PopupBlockEntityRenderer::new); + BlockEntityRendererFactories.register(Glowcase.SPRITE_BLOCK_ENTITY.get(), SpriteBlockEntityRenderer::new); WorldRenderEvents.AFTER_TRANSLUCENT.register(BakedBlockEntityRenderer.Manager::render); InvalidateRenderStateCallback.EVENT.register(BakedBlockEntityRenderer.Manager::reset); diff --git a/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClientProxy.java b/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClientProxy.java index 2cf548d..6582ed2 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClientProxy.java +++ b/src/main/java/dev/hephaestus/glowcase/client/GlowcaseClientProxy.java @@ -3,10 +3,15 @@ import dev.hephaestus.glowcase.GlowcaseCommonProxy; import dev.hephaestus.glowcase.block.entity.HyperlinkBlockEntity; import dev.hephaestus.glowcase.block.entity.ItemDisplayBlockEntity; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; import dev.hephaestus.glowcase.client.gui.screen.ingame.HyperlinkBlockEditScreen; import dev.hephaestus.glowcase.client.gui.screen.ingame.ItemDisplayBlockEditScreen; import dev.hephaestus.glowcase.client.gui.screen.ingame.TextBlockEditScreen; +import dev.hephaestus.glowcase.client.gui.screen.ingame.PopupBlockEditScreen; +import dev.hephaestus.glowcase.client.gui.screen.ingame.PopupBlockViewScreen; +import dev.hephaestus.glowcase.client.gui.screen.ingame.SpriteBlockEditScreen; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ConfirmLinkScreen; import net.minecraft.util.math.BlockPos; @@ -40,4 +45,28 @@ public void openTextBlockEditScreen(BlockPos pos) { MinecraftClient.getInstance().setScreen(new TextBlockEditScreen(be)); } } + + @Override + public void openPopupBlockEditScreen(BlockPos pos) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world != null && client.world.getBlockEntity(pos) instanceof PopupBlockEntity be) { + MinecraftClient.getInstance().setScreen(new PopupBlockEditScreen(be)); + } + } + + @Override + public void openPopupBlockViewScreen(BlockPos pos) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world != null && client.world.getBlockEntity(pos) instanceof PopupBlockEntity be) { + MinecraftClient.getInstance().setScreen(new PopupBlockViewScreen(be)); + } + } + + @Override + public void openSpriteBlockEditScreen(BlockPos pos) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world != null && client.world.getBlockEntity(pos) instanceof SpriteBlockEntity be) { + MinecraftClient.getInstance().setScreen(new SpriteBlockEditScreen(be)); + } + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java new file mode 100644 index 0000000..ce8469f --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java @@ -0,0 +1,329 @@ +package dev.hephaestus.glowcase.client.gui.screen.ingame; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import dev.hephaestus.glowcase.block.entity.HyperlinkBlockEntity; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import dev.hephaestus.glowcase.packet.C2SEditPopupBlock; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.render.*; +import net.minecraft.client.util.SelectionManager; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +//TODO: multi-character selection at some point? it may be a bit complex but it'd be nice +public class PopupBlockEditScreen extends GlowcaseScreen { + private final PopupBlockEntity popupBlockEntity; + + private SelectionManager selectionManager; + private int currentRow; + private long ticksSinceOpened = 0; + private TextFieldWidget titleEntryWidget; + private ButtonWidget changeAlignment; + private TextFieldWidget colorEntryWidget; + + public PopupBlockEditScreen(PopupBlockEntity popupBlockEntity) { + this.popupBlockEntity = popupBlockEntity; + } + + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) { + renderDarkening(context); + } + + @Override + public void init() { + super.init(); + + int innerPadding = width / 100; + + this.selectionManager = new SelectionManager( + () -> this.popupBlockEntity.getRawLine(this.currentRow), + (string) -> { + popupBlockEntity.setRawLine(this.currentRow, string); + this.popupBlockEntity.renderDirty = true; + }, + SelectionManager.makeClipboardGetter(this.client), + SelectionManager.makeClipboardSetter(this.client), + (string) -> true); + + this.titleEntryWidget = new TextFieldWidget(this.client.textRenderer, width / 10, 0, 8 * width / 10, 20, Text.empty()); + this.titleEntryWidget.setMaxLength(HyperlinkBlockEntity.TITLE_MAX_LENGTH); + this.titleEntryWidget.setText(this.popupBlockEntity.title); + this.titleEntryWidget.setPlaceholder(Text.translatable("gui.glowcase.title")); + this.titleEntryWidget.setChangedListener(string -> { + this.popupBlockEntity.title = this.titleEntryWidget.getText(); + this.popupBlockEntity.renderDirty = true; + }); + + this.changeAlignment = ButtonWidget.builder(Text.stringifiedTranslatable("gui.glowcase.alignment", this.popupBlockEntity.textAlignment), action -> { + switch (popupBlockEntity.textAlignment) { + case LEFT -> popupBlockEntity.textAlignment = TextBlockEntity.TextAlignment.CENTER; + case CENTER -> popupBlockEntity.textAlignment = TextBlockEntity.TextAlignment.RIGHT; + case RIGHT -> popupBlockEntity.textAlignment = TextBlockEntity.TextAlignment.LEFT; + } + this.popupBlockEntity.renderDirty = true; + + this.changeAlignment.setMessage(Text.stringifiedTranslatable("gui.glowcase.alignment", this.popupBlockEntity.textAlignment)); + }).dimensions(120 + innerPadding, 20 + innerPadding, 160, 20).build(); + + this.colorEntryWidget = new TextFieldWidget(this.client.textRenderer, 280 + innerPadding * 2, 20 + innerPadding, 50, 20, Text.empty()); + this.colorEntryWidget.setText("#" + Integer.toHexString(this.popupBlockEntity.color & 0x00FFFFFF)); + this.colorEntryWidget.setChangedListener(string -> { + TextColor.parse(this.colorEntryWidget.getText()).ifSuccess(color -> { + this.popupBlockEntity.color = color == null ? 0xFFFFFFFF : color.getRgb() | 0xFF000000; + this.popupBlockEntity.renderDirty = true; + }); + }); + + this.addDrawableChild(this.titleEntryWidget); + this.addDrawableChild(this.changeAlignment); + this.addDrawableChild(this.colorEntryWidget); + } + + @Override + public void tick() { + ++this.ticksSinceOpened; + } + + @Override + public void close() { + C2SEditPopupBlock.of(popupBlockEntity).send(); + super.close(); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + if (this.client != null) { + super.render(context, mouseX, mouseY, delta); + + context.getMatrices().push(); + context.getMatrices().translate(0, 40 + 2 * this.width / 100F, 0); + for (int i = 0; i < this.popupBlockEntity.lines.size(); ++i) { + var text = this.currentRow == i ? Text.literal(this.popupBlockEntity.getRawLine(i)) : this.popupBlockEntity.lines.get(i); + + int lineWidth = this.textRenderer.getWidth(text); + switch (this.popupBlockEntity.textAlignment) { + case LEFT -> context.drawTextWithShadow(client.textRenderer, text, this.width / 10, i * 12, this.popupBlockEntity.color); + case CENTER -> context.drawTextWithShadow(client.textRenderer, text, this.width / 2 - lineWidth / 2, i * 12, this.popupBlockEntity.color); + case RIGHT -> context.drawTextWithShadow(client.textRenderer, text, this.width - this.width / 10 - lineWidth, i * 12, this.popupBlockEntity.color); + } + } + + int caretStart = this.selectionManager.getSelectionStart(); + int caretEnd = this.selectionManager.getSelectionEnd(); + + if (caretStart >= 0) { + String line = this.popupBlockEntity.getRawLine(this.currentRow); + int selectionStart = MathHelper.clamp(Math.min(caretStart, caretEnd), 0, line.length()); + int selectionEnd = MathHelper.clamp(Math.max(caretStart, caretEnd), 0, line.length()); + + String preSelection = line.substring(0, MathHelper.clamp(line.length(), 0, selectionStart)); + int startX = this.client.textRenderer.getWidth(preSelection); + + float push = switch (this.popupBlockEntity.textAlignment) { + case LEFT -> this.width / 10F; + case CENTER -> this.width / 2F - this.textRenderer.getWidth(line) / 2F; + case RIGHT -> this.width - this.width / 10F - this.textRenderer.getWidth(line); + }; + + startX += (int) push; + + + int caretStartY = this.currentRow * 12; + int caretEndY = this.currentRow * 12 + 9; + if (this.ticksSinceOpened / 6 % 2 == 0 && !this.titleEntryWidget.isActive() && !this.colorEntryWidget.isActive()) { + if (selectionStart < line.length()) { + context.fill(startX, caretStartY, startX + 1, caretEndY, 0xCCFFFFFF); + } else { + context.drawText(client.textRenderer, "_", startX, this.currentRow * 12, 0xFFFFFFFF, false); + } + } + + if (caretStart != caretEnd) { + int endX = startX + this.client.textRenderer.getWidth(line.substring(selectionStart, selectionEnd)); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + RenderSystem.enableColorLogicOp(); + RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE); + bufferBuilder.vertex(context.getMatrices().peek().getPositionMatrix(), startX, caretEndY, 0.0F).color(0, 0, 255, 255); + bufferBuilder.vertex(context.getMatrices().peek().getPositionMatrix(), endX, caretEndY, 0.0F).color(0, 0, 255, 255); + bufferBuilder.vertex(context.getMatrices().peek().getPositionMatrix(), endX, caretStartY, 0.0F).color(0, 0, 255, 255); + bufferBuilder.vertex(context.getMatrices().peek().getPositionMatrix(), startX, caretStartY, 0.0F).color(0, 0, 255, 255); + BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); + RenderSystem.disableColorLogicOp(); + } + } + + context.getMatrices().pop(); + } + } + + @Override + public boolean charTyped(char chr, int keyCode) { + if (this.titleEntryWidget.isActive()) { + return this.titleEntryWidget.charTyped(chr, keyCode); + } else if (this.colorEntryWidget.isActive()) { + return this.colorEntryWidget.charTyped(chr, keyCode); + } else { + this.selectionManager.insert(chr); + return true; + } + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (this.titleEntryWidget.isActive()) { + if (keyCode == GLFW.GLFW_KEY_ESCAPE) { + this.close(); + return true; + } else { + return this.titleEntryWidget.keyPressed(keyCode, scanCode, modifiers); + } + } else if (this.colorEntryWidget.isActive()) { + if (keyCode == GLFW.GLFW_KEY_ESCAPE) { + this.close(); + return true; + } else { + return this.colorEntryWidget.keyPressed(keyCode, scanCode, modifiers); + } + } else { + setFocused(null); + if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) { + this.popupBlockEntity.addRawLine(this.currentRow + 1, + this.popupBlockEntity.getRawLine(this.currentRow).substring( + MathHelper.clamp(this.selectionManager.getSelectionStart(), 0, this.popupBlockEntity.getRawLine(this.currentRow).length()) + )); + this.popupBlockEntity.setRawLine(this.currentRow, + this.popupBlockEntity.getRawLine(this.currentRow).substring(0, MathHelper.clamp(this.selectionManager.getSelectionStart(), 0, this.popupBlockEntity.getRawLine(this.currentRow).length()) + )); + this.popupBlockEntity.renderDirty = true; + ++this.currentRow; + this.selectionManager.moveCursorToStart(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_UP) { + this.currentRow = Math.max(this.currentRow - 1, 0); + this.selectionManager.putCursorAtEnd(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_DOWN) { + this.currentRow = Math.min(this.currentRow + 1, (this.popupBlockEntity.lines.size() - 1)); + this.selectionManager.putCursorAtEnd(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_BACKSPACE && this.currentRow > 0 && this.popupBlockEntity.lines.size() > 1 && this.selectionManager.getSelectionStart() == 0 && this.selectionManager.getSelectionEnd() == this.selectionManager.getSelectionStart()) { + --this.currentRow; + this.selectionManager.putCursorAtEnd(); + deleteLine(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_DELETE && this.currentRow < this.popupBlockEntity.lines.size() - 1 && this.selectionManager.getSelectionEnd() == this.popupBlockEntity.getRawLine(this.currentRow).length()) { + deleteLine(); + return true; + } else { + try { + boolean val = this.selectionManager.handleSpecialKey(keyCode) || super.keyPressed(keyCode, scanCode, modifiers); + int selectionOffset = this.popupBlockEntity.getRawLine(this.currentRow).length() - this.selectionManager.getSelectionStart(); + + // Find line feed characters and create proper newlines + for (int i = 0; i < this.popupBlockEntity.lines.size(); ++i) { + int lineFeedIndex = this.popupBlockEntity.getRawLine(i).indexOf("\n"); + + if (lineFeedIndex >= 0) { + this.popupBlockEntity.addRawLine(i + 1, + this.popupBlockEntity.getRawLine(i).substring( + MathHelper.clamp(lineFeedIndex + 1, 0, this.popupBlockEntity.getRawLine(i).length()) + )); + this.popupBlockEntity.setRawLine(i, + this.popupBlockEntity.getRawLine(i).substring(0, MathHelper.clamp(lineFeedIndex, 0, this.popupBlockEntity.getRawLine(i).length()) + )); + this.popupBlockEntity.renderDirty = true; + ++this.currentRow; + this.selectionManager.putCursorAtEnd(); + this.selectionManager.moveCursor(-selectionOffset); + } + } + return val; + } catch (StringIndexOutOfBoundsException e) { + e.printStackTrace(); + MinecraftClient.getInstance().setScreen(null); + return false; + } + } + } + } + + private void deleteLine() { + this.popupBlockEntity.setRawLine(this.currentRow, + this.popupBlockEntity.getRawLine(this.currentRow) + this.popupBlockEntity.getRawLine(this.currentRow + 1) + ); + + this.popupBlockEntity.lines.remove(this.currentRow + 1); + this.popupBlockEntity.renderDirty = true; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + int topOffset = (int) (40 + 2 * this.width / 100F); + if (!this.titleEntryWidget.mouseClicked(mouseX, mouseY, button)) { + this.titleEntryWidget.setFocused(false); + } + if (!this.colorEntryWidget.mouseClicked(mouseX, mouseY, button)) { + this.colorEntryWidget.setFocused(false); + } + if (mouseY > topOffset) { + this.currentRow = MathHelper.clamp((int) (mouseY - topOffset) / 12, 0, this.popupBlockEntity.lines.size() - 1); + this.setFocused(null); + String baseContents = this.popupBlockEntity.getRawLine(currentRow); + int baseContentsWidth = this.textRenderer.getWidth(baseContents); + int contentsStart; + int contentsEnd; + switch (this.popupBlockEntity.textAlignment) { + case LEFT -> { + contentsStart = this.width / 10; + contentsEnd = contentsStart + baseContentsWidth; + } + case CENTER -> { + int midpoint = this.width / 2; + int textMidpoint = baseContentsWidth / 2; + contentsStart = midpoint - textMidpoint; + contentsEnd = midpoint + textMidpoint; + } + case RIGHT -> { + contentsEnd = this.width - this.width / 10; + contentsStart = contentsEnd - baseContentsWidth; + } + //even though this is exhaustive, javac won't treat contentsStart and contentsEnd as initialized + //why? who knows! just throw bc this should be impossible + default -> throw new IllegalStateException(":HOW:"); + } + + if (mouseX <= contentsStart) { + this.selectionManager.moveCursorToStart(); + } else if (mouseX >= contentsEnd) { + this.selectionManager.putCursorAtEnd(); + } else { + int lastWidth = 0; + for (int i = 1; i < baseContents.length(); i++) { + String testContents = baseContents.substring(0, i); + int width = this.textRenderer.getWidth(testContents); + int midpointWidth = (width + lastWidth) / 2; + if (mouseX < contentsStart + midpointWidth) { + this.selectionManager.moveCursorTo(i - 1, false); + break; + } else if (mouseX <= contentsStart + width) { + this.selectionManager.moveCursorTo(i, false); + break; + } + lastWidth = width; + } + } + return true; + } else { + return super.mouseClicked(mouseX, mouseY, button); + } + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockViewScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockViewScreen.java new file mode 100644 index 0000000..9ad6fe5 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockViewScreen.java @@ -0,0 +1,52 @@ +package dev.hephaestus.glowcase.client.gui.screen.ingame; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.render.*; +import net.minecraft.client.util.SelectionManager; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +//TODO: multi-character selection at some point? it may be a bit complex but it'd be nice +public class PopupBlockViewScreen extends GlowcaseScreen { + private final PopupBlockEntity popupBlockEntity; + + public PopupBlockViewScreen(PopupBlockEntity popupBlockEntity) { + this.popupBlockEntity = popupBlockEntity; + } + + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) { + renderDarkening(context); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + if (this.client != null) { + super.render(context, mouseX, mouseY, delta); + + context.getMatrices().push(); + context.getMatrices().translate(0, 40 + 2 * this.width / 100F, 0); + for (int i = 0; i < this.popupBlockEntity.lines.size(); ++i) { + var text = this.popupBlockEntity.lines.get(i); + + int lineWidth = this.textRenderer.getWidth(text); + switch (this.popupBlockEntity.textAlignment) { + case LEFT -> context.drawTextWithShadow(client.textRenderer, text, this.width / 10, i * 12, this.popupBlockEntity.color); + case CENTER -> context.drawTextWithShadow(client.textRenderer, text, this.width / 2 - lineWidth / 2, i * 12, this.popupBlockEntity.color); + case RIGHT -> context.drawTextWithShadow(client.textRenderer, text, this.width - this.width / 10 - lineWidth, i * 12, this.popupBlockEntity.color); + } + } + + context.getMatrices().pop(); + } + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java new file mode 100644 index 0000000..7e21327 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java @@ -0,0 +1,75 @@ +package dev.hephaestus.glowcase.client.gui.screen.ingame; + +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; +import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import dev.hephaestus.glowcase.packet.C2SEditSpriteBlock; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.Identifier; + +public class SpriteBlockEditScreen extends GlowcaseScreen { + private final SpriteBlockEntity spriteBlockEntity; + + private TextFieldWidget spriteWidget; + private ButtonWidget rotationWidget; + private ButtonWidget zOffsetToggle; + private TextFieldWidget colorEntryWidget; + + public SpriteBlockEditScreen(SpriteBlockEntity spriteBlockEntity) { + this.spriteBlockEntity = spriteBlockEntity; + } + + @Override + public void init() { + super.init(); + + if (this.client == null) return; + + this.spriteWidget = new TextFieldWidget(this.client.textRenderer, width / 2 - 75, height / 2 - 55, 150, 20, Text.empty()); + this.spriteWidget.setText(spriteBlockEntity.sprite); + this.spriteWidget.setChangedListener(string -> { + if (Identifier.isPathValid(this.spriteWidget.getText())) { + this.spriteBlockEntity.sprite = this.spriteWidget.getText(); + } + }); + + this.rotationWidget = ButtonWidget.builder(Text.literal("Rotate"), (action) -> { + this.spriteBlockEntity.rotation += 45; + if (this.spriteBlockEntity.rotation >= 360) { + this.spriteBlockEntity.rotation = 0; + } + }).dimensions(width / 2 - 75, height / 2 - 25, 150, 20).build(); + + this.zOffsetToggle = ButtonWidget.builder(Text.literal(this.spriteBlockEntity.zOffset.name()), action -> { + switch (spriteBlockEntity.zOffset) { + case FRONT -> spriteBlockEntity.zOffset = TextBlockEntity.ZOffset.CENTER; + case CENTER -> spriteBlockEntity.zOffset = TextBlockEntity.ZOffset.BACK; + case BACK -> spriteBlockEntity.zOffset = TextBlockEntity.ZOffset.FRONT; + } + + this.zOffsetToggle.setMessage(Text.literal(this.spriteBlockEntity.zOffset.name())); + }).dimensions(width / 2 - 75, height / 2 + 5, 150, 20).build(); + + this.colorEntryWidget = new TextFieldWidget(this.client.textRenderer, width / 2 - 75, height / 2 + 35, 150, 20, Text.empty()); + this.colorEntryWidget.setText("#" + String.format("%1$06X", this.spriteBlockEntity.color & 0x00FFFFFF)); + this.colorEntryWidget.setChangedListener(string -> { + TextColor.parse(this.colorEntryWidget.getText()).ifSuccess(color -> { + this.spriteBlockEntity.color = color == null ? 0xFFFFFFFF : color.getRgb() | 0xFF000000; + }); + }); + + this.addDrawableChild(this.spriteWidget); + this.addDrawableChild(this.rotationWidget); + this.addDrawableChild(this.zOffsetToggle); + this.addDrawableChild(this.colorEntryWidget); + } + + @Override + public void close() { + spriteBlockEntity.setSprite(spriteWidget.getText()); + C2SEditSpriteBlock.of(spriteBlockEntity).send(); + super.close(); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index ae97861..05af351 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -89,7 +89,7 @@ public void init() { }).dimensions(120 + innerPadding, 20 + innerPadding, 160, 20).build(); this.colorEntryWidget = new TextFieldWidget(this.client.textRenderer, 280 + innerPadding * 2, 0, 50, 20, Text.empty()); - this.colorEntryWidget.setText("#" + Integer.toHexString(this.textBlockEntity.color & 0x00FFFFFF)); + this.colorEntryWidget.setText("#" + String.format("%1$06X", this.textBlockEntity.color & 0x00FFFFFF)); this.colorEntryWidget.setChangedListener(string -> { TextColor.parse(this.colorEntryWidget.getText()).ifSuccess(color -> { this.textBlockEntity.color = color == null ? 0xFFFFFFFF : color.getRgb() | 0xFF000000; diff --git a/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/HyperlinkBlockEntityRenderer.java b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/HyperlinkBlockEntityRenderer.java index 264cc1a..066e36f 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/HyperlinkBlockEntityRenderer.java +++ b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/HyperlinkBlockEntityRenderer.java @@ -30,14 +30,14 @@ public void render(HyperlinkBlockEntity entity, float f, MatrixStack matrices, V float n = -camera.getYaw(); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(n)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180)); context.getItemRenderer().renderItem(STACK, ModelTransformationMode.FIXED, light, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers, entity.getWorld(), 0); HitResult hitResult = mc.crosshairTarget; if (hitResult instanceof BlockHitResult && ((BlockHitResult) hitResult).getBlockPos().equals(entity.getPos())) { float scale = 0.025F; matrices.scale(scale, scale, scale); - matrices.translate(-context.getTextRenderer().getWidth(entity.getText()) / 2F, -4, scale); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180)); + matrices.translate(-context.getTextRenderer().getWidth(entity.getText()) / 2F, -4, -scale); // Fixes shadow being rendered in front of actual text matrices.scale(1, 1, -1); context.getTextRenderer().draw(entity.getText(), 0, 0, 0xFFFFFF, true, matrices.peek().getPositionMatrix(), vertexConsumers, TextLayerType.NORMAL, 0, LightmapTextureManager.MAX_LIGHT_COORDINATE); diff --git a/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/PopupBlockEntityRenderer.java b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/PopupBlockEntityRenderer.java new file mode 100644 index 0000000..1c0ffa3 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/PopupBlockEntityRenderer.java @@ -0,0 +1,47 @@ +package dev.hephaestus.glowcase.client.render.block.entity; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer.TextLayerType; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; +import net.minecraft.client.render.model.json.ModelTransformationMode; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.RotationAxis; + +public record PopupBlockEntityRenderer(BlockEntityRendererFactory.Context context) implements BlockEntityRenderer { + private static final MinecraftClient mc = MinecraftClient.getInstance(); + + public static final ItemStack STACK = new ItemStack(Glowcase.POPUP_BLOCK.get()); + + public void render(PopupBlockEntity entity, float f, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) { + Camera camera = context.getRenderDispatcher().camera; + matrices.push(); + matrices.translate(0.5D, 0.5D, 0.5D); + matrices.scale(0.5F, 0.5F, 0.5F); + float n = -camera.getYaw(); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(n)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); + context.getItemRenderer().renderItem(STACK, ModelTransformationMode.FIXED, light, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers, entity.getWorld(), 0); + + HitResult hitResult = mc.crosshairTarget; + if (hitResult instanceof BlockHitResult && ((BlockHitResult) hitResult).getBlockPos().equals(entity.getPos())) { + float scale = 0.025F; + matrices.scale(scale, scale, scale); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180)); + matrices.translate(-context.getTextRenderer().getWidth(entity.title) / 2F, -4, -scale); + // Fixes shadow being rendered in front of actual text + matrices.scale(1, 1, -1); + context.getTextRenderer().draw(entity.title, 0, 0, 0xFFFFFF, true, matrices.peek().getPositionMatrix(), vertexConsumers, TextLayerType.NORMAL, 0, LightmapTextureManager.MAX_LIGHT_COORDINATE); + } + matrices.pop(); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/SpriteBlockEntityRenderer.java b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/SpriteBlockEntityRenderer.java new file mode 100644 index 0000000..b23ce31 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/render/block/entity/SpriteBlockEntityRenderer.java @@ -0,0 +1,55 @@ +package dev.hephaestus.glowcase.client.render.block.entity; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; +import net.minecraft.client.render.*; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.state.property.Properties; +import net.minecraft.util.math.RotationAxis; +import org.joml.Vector3f; + +public record SpriteBlockEntityRenderer(BlockEntityRendererFactory.Context context) implements BlockEntityRenderer { + private static final Vector3f[] vertices = new Vector3f[] { + new Vector3f(-0.5F, -0.5F, 0.0F), + new Vector3f(0.5F, -0.5F, 0.0F), + new Vector3f(0.5F, 0.5F, 0.0F), + new Vector3f(-0.5F, 0.5F, 0.0F) + }; + + public void render(SpriteBlockEntity entity, float f, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) { + matrices.push(); + matrices.translate(0.5D, 0.5D, 0.5D); + + float rotation = -(entity.getCachedState().get(Properties.ROTATION) * 360) / 16.0F; + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(rotation)); + matrices.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(entity.rotation)); + + switch (entity.zOffset) { + case FRONT -> matrices.translate(0D, 0D, 0.4D); + case BACK -> matrices.translate(0D, 0D, -0.4D); + } + + var entry = matrices.peek(); + var vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutout(Glowcase.id("textures/sprite/" + entity.sprite + ".png"))); + + vertex(entry, vertexConsumer, vertices[0], 0, 1, entity.color); + vertex(entry, vertexConsumer, vertices[1], 1, 1, entity.color); + vertex(entry, vertexConsumer, vertices[2], 1, 0, entity.color); + vertex(entry, vertexConsumer, vertices[3], 0, 0, entity.color); + + matrices.pop(); + } + + private void vertex( + MatrixStack.Entry matrix, VertexConsumer vertexConsumer, Vector3f vertex, float u, float v, + int color) { + vertexConsumer.vertex(matrix, vertex.x(), vertex.y(), vertex.z()) + .color(color) + .texture(u, v) + .overlay(OverlayTexture.DEFAULT_UV) + .light(LightmapTextureManager.MAX_LIGHT_COORDINATE) + .normal(0, 1, 0); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/packet/C2SEditPopupBlock.java b/src/main/java/dev/hephaestus/glowcase/packet/C2SEditPopupBlock.java new file mode 100644 index 0000000..7732cbc --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/packet/C2SEditPopupBlock.java @@ -0,0 +1,54 @@ +package dev.hephaestus.glowcase.packet; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.HyperlinkBlockEntity; +import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; +import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.List; + +public record C2SEditPopupBlock(BlockPos pos, String title, List lines, TextBlockEntity.TextAlignment alignment, int color) implements C2SEditBlockEntity { + public static final Id ID = new Id<>(Glowcase.id("channel.popup_block")); + public static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + BlockPos.PACKET_CODEC, C2SEditPopupBlock::pos, + PacketCodecs.STRING, C2SEditPopupBlock::title, + PacketCodecs.collection(ArrayList::new, TextCodecs.REGISTRY_PACKET_CODEC), C2SEditPopupBlock::lines, + PacketCodecs.BYTE.xmap(index -> TextBlockEntity.TextAlignment.values()[index], textAlignment -> (byte) textAlignment.ordinal()), C2SEditPopupBlock::alignment, + PacketCodecs.INTEGER, C2SEditPopupBlock::color, + C2SEditPopupBlock::new + ); + + public static C2SEditPopupBlock of(PopupBlockEntity be) { + return new C2SEditPopupBlock(be.getPos(), be.title, be.lines, be.textAlignment, be.color); + } + + @Override + public Id getId() { + return ID; + } + + @Override + public void receive(ServerWorld world, BlockEntity blockEntity) { + if (!(blockEntity instanceof PopupBlockEntity be)) return; + + if (this.title().length() <= HyperlinkBlockEntity.TITLE_MAX_LENGTH) { + be.title = this.title(); + } + be.lines = this.lines(); + be.textAlignment = this.alignment(); + be.color = this.color(); + + be.markDirty(); + be.dispatch(); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/packet/C2SEditSpriteBlock.java b/src/main/java/dev/hephaestus/glowcase/packet/C2SEditSpriteBlock.java new file mode 100644 index 0000000..4ba3597 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/packet/C2SEditSpriteBlock.java @@ -0,0 +1,46 @@ +package dev.hephaestus.glowcase.packet; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.block.entity.SpriteBlockEntity; +import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; + +public record C2SEditSpriteBlock(BlockPos pos, String sprite, int rotation, TextBlockEntity.ZOffset offset, int color) implements C2SEditBlockEntity { + public static final Id ID = new Id<>(Glowcase.id("channel.sprite.save")); + public static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + BlockPos.PACKET_CODEC, C2SEditSpriteBlock::pos, + PacketCodecs.STRING, C2SEditSpriteBlock::sprite, + PacketCodecs.INTEGER, C2SEditSpriteBlock::rotation, + PacketCodecs.INTEGER.xmap(index -> TextBlockEntity.ZOffset.values()[index], TextBlockEntity.ZOffset::ordinal), C2SEditSpriteBlock::offset, + PacketCodecs.INTEGER, C2SEditSpriteBlock::color, + C2SEditSpriteBlock::new + ); + + public static C2SEditSpriteBlock of(SpriteBlockEntity be) { + return new C2SEditSpriteBlock(be.getPos(), be.sprite, be.rotation, be.zOffset, be.color); + } + + @Override + public Id getId() { + return ID; + } + + @Override + public void receive(ServerWorld world, BlockEntity blockEntity) { + if (!(blockEntity instanceof SpriteBlockEntity be)) return; + + be.setSprite(this.sprite()); + be.rotation = this.rotation(); + be.zOffset = this.offset(); + be.color = this.color(); + + be.markDirty(); + be.dispatch(); + } +} diff --git a/src/main/resources/assets/glowcase/blockstates/popup_block.json b/src/main/resources/assets/glowcase/blockstates/popup_block.json new file mode 100644 index 0000000..0858580 --- /dev/null +++ b/src/main/resources/assets/glowcase/blockstates/popup_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "glowcase:block/popup_block" + } + } +} diff --git a/src/main/resources/assets/glowcase/blockstates/sprite_block.json b/src/main/resources/assets/glowcase/blockstates/sprite_block.json new file mode 100644 index 0000000..eb3ed52 --- /dev/null +++ b/src/main/resources/assets/glowcase/blockstates/sprite_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "glowcase:block/glowcase_block" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/glowcase/lang/en_us.json b/src/main/resources/assets/glowcase/lang/en_us.json index 700e588..84c8cec 100644 --- a/src/main/resources/assets/glowcase/lang/en_us.json +++ b/src/main/resources/assets/glowcase/lang/en_us.json @@ -3,6 +3,8 @@ "block.glowcase.text_block": "Text Block", "block.glowcase.hyperlink_block": "Hyperlink Block", "block.glowcase.item_display_block": "Item Display Block", + "block.glowcase.popup_block": "Popup Block", + "block.glowcase.sprite_block": "Sprite Block", "gui.glowcase.scale": "Scale: %d", "gui.glowcase.alignment": "Alignment: %s", "gui.glowcase.gives_item": "Gives Item: %s", @@ -25,5 +27,9 @@ "block.glowcase.item_display_block.tooltip.0": "Gives an item stack when interacted", "block.glowcase.item_display_block.tooltip.1": "Interact with an item stack to set it", "block.glowcase.item_display_block.tooltip.2": "Interact with the same item to edit", + "block.glowcase.popup_block.tooltip.0": "Displays formatted text when interacted", + "block.glowcase.popup_block.tooltip.1": "Supports Placeholder QuickText", + "block.glowcase.sprite_block.tooltip.0": "Displays a sprite", + "block.glowcase.sprite_block.tooltip.1": "Can be extended with resource packs", "item.glowcase.lock.tooltip.0": "Locks and unlocks containers" } diff --git a/src/main/resources/assets/glowcase/models/block/popup_block.json b/src/main/resources/assets/glowcase/models/block/popup_block.json new file mode 100644 index 0000000..49f3a0b --- /dev/null +++ b/src/main/resources/assets/glowcase/models/block/popup_block.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "glowcase:item/popup_block" + } +} diff --git a/src/main/resources/assets/glowcase/models/item/popup_block.json b/src/main/resources/assets/glowcase/models/item/popup_block.json new file mode 100644 index 0000000..898e040 --- /dev/null +++ b/src/main/resources/assets/glowcase/models/item/popup_block.json @@ -0,0 +1,49 @@ +{ + "textures": { + "0": "glowcase:item/popup_block", + "particle": "glowcase:item/popup_block" + }, + "elements": [ + { + "from": [ + 2, + 2, + 8 + ], + "to": [ + 14, + 14, + 8 + ], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [ + 8, + 8, + 16 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 0, + 16, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 0, + 16, + 16 + ], + "texture": "#0" + } + } + } + ] +} diff --git a/src/main/resources/assets/glowcase/models/item/sprite_block.json b/src/main/resources/assets/glowcase/models/item/sprite_block.json new file mode 100644 index 0000000..fad38b9 --- /dev/null +++ b/src/main/resources/assets/glowcase/models/item/sprite_block.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "glowcase:item/sprite_block" + } +} diff --git a/src/main/resources/assets/glowcase/textures/item/popup_block.png b/src/main/resources/assets/glowcase/textures/item/popup_block.png new file mode 100644 index 0000000..9a17e05 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/item/popup_block.png differ diff --git a/src/main/resources/assets/glowcase/textures/item/sprite_block.png b/src/main/resources/assets/glowcase/textures/item/sprite_block.png new file mode 100644 index 0000000..00b7df6 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/item/sprite_block.png differ diff --git a/src/main/resources/assets/glowcase/textures/item/text_block.png b/src/main/resources/assets/glowcase/textures/item/text_block.png index 9b83597..16b82fb 100644 Binary files a/src/main/resources/assets/glowcase/textures/item/text_block.png and b/src/main/resources/assets/glowcase/textures/item/text_block.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/arrow.png b/src/main/resources/assets/glowcase/textures/sprite/arrow.png new file mode 100644 index 0000000..02dc5bb Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/checkmark.png b/src/main/resources/assets/glowcase/textures/sprite/checkmark.png new file mode 100644 index 0000000..bc729a9 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/checkmark.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/double_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/double_arrow.png new file mode 100644 index 0000000..8c8abf1 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/double_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/double_line_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/double_line_arrow.png new file mode 100644 index 0000000..145b649 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/double_line_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/exclamation.png b/src/main/resources/assets/glowcase/textures/sprite/exclamation.png new file mode 100644 index 0000000..0cb1c70 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/exclamation.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/fancy_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/fancy_arrow.png new file mode 100644 index 0000000..12ab41b Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/fancy_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/information.png b/src/main/resources/assets/glowcase/textures/sprite/information.png new file mode 100644 index 0000000..c50e34b Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/information.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/interrobang.png b/src/main/resources/assets/glowcase/textures/sprite/interrobang.png new file mode 100644 index 0000000..1fc52db Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/interrobang.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/no_entry.png b/src/main/resources/assets/glowcase/textures/sprite/no_entry.png new file mode 100644 index 0000000..f7ccac7 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/no_entry.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/o.png b/src/main/resources/assets/glowcase/textures/sprite/o.png new file mode 100644 index 0000000..5359841 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/o.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/question.png b/src/main/resources/assets/glowcase/textures/sprite/question.png new file mode 100644 index 0000000..7dc7c1e Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/question.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/real_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/real_arrow.png new file mode 100644 index 0000000..e3d1cb5 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/real_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/small_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/small_arrow.png new file mode 100644 index 0000000..af6dcd2 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/small_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/triple_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/triple_arrow.png new file mode 100644 index 0000000..a9db5b2 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/triple_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/triple_line_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/triple_line_arrow.png new file mode 100644 index 0000000..fe10c77 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/triple_line_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/wide_arrow.png b/src/main/resources/assets/glowcase/textures/sprite/wide_arrow.png new file mode 100644 index 0000000..ea73088 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/wide_arrow.png differ diff --git a/src/main/resources/assets/glowcase/textures/sprite/x.png b/src/main/resources/assets/glowcase/textures/sprite/x.png new file mode 100644 index 0000000..cc639e6 Binary files /dev/null and b/src/main/resources/assets/glowcase/textures/sprite/x.png differ diff --git a/src/main/resources/data/glowcase/tags/item/items.json b/src/main/resources/data/glowcase/tags/item/items.json index 26dc5c1..074b39c 100644 --- a/src/main/resources/data/glowcase/tags/item/items.json +++ b/src/main/resources/data/glowcase/tags/item/items.json @@ -3,6 +3,8 @@ "values": [ "glowcase:hyperlink_block", "glowcase:item_display_block", - "glowcase:text_block" + "glowcase:text_block", + "glowcase:popup_block", + "glowcase:sprite_block" ] }