diff --git a/src/generated/resources/assets/naturesaura/blockstates/aura_timer.json b/src/generated/resources/assets/naturesaura/blockstates/aura_timer.json new file mode 100644 index 00000000..2a8b50fb --- /dev/null +++ b/src/generated/resources/assets/naturesaura/blockstates/aura_timer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "naturesaura:block/aura_timer" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/naturesaura/models/item/aura_timer.json b/src/generated/resources/assets/naturesaura/models/item/aura_timer.json new file mode 100644 index 00000000..7552299b --- /dev/null +++ b/src/generated/resources/assets/naturesaura/models/item/aura_timer.json @@ -0,0 +1,3 @@ +{ + "parent": "naturesaura:block/aura_timer" +} \ No newline at end of file diff --git a/src/generated/resources/data/naturesaura/loot_tables/blocks/aura_timer.json b/src/generated/resources/data/naturesaura/loot_tables/blocks/aura_timer.json new file mode 100644 index 00000000..9e616b2b --- /dev/null +++ b/src/generated/resources/data/naturesaura/loot_tables/blocks/aura_timer.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "naturesaura:aura_timer" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/BlockAuraTimer.java b/src/main/java/de/ellpeck/naturesaura/blocks/BlockAuraTimer.java new file mode 100644 index 00000000..a477e42b --- /dev/null +++ b/src/main/java/de/ellpeck/naturesaura/blocks/BlockAuraTimer.java @@ -0,0 +1,103 @@ +package de.ellpeck.naturesaura.blocks; + +import de.ellpeck.naturesaura.Helper; +import de.ellpeck.naturesaura.blocks.tiles.ModTileEntities; +import de.ellpeck.naturesaura.blocks.tiles.TileEntityAuraTimer; +import de.ellpeck.naturesaura.blocks.tiles.render.RenderAuraTimer; +import de.ellpeck.naturesaura.blocks.tiles.render.RenderProjectileGenerator; +import de.ellpeck.naturesaura.data.BlockStateGenerator; +import de.ellpeck.naturesaura.reg.ICustomBlockState; +import de.ellpeck.naturesaura.reg.ICustomRenderType; +import de.ellpeck.naturesaura.reg.ITESRProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.Tuple; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.Random; +import java.util.function.Function; +import java.util.function.Supplier; + +public class BlockAuraTimer extends BlockContainerImpl implements ICustomBlockState, ITESRProvider, ICustomRenderType { + + private static final VoxelShape SHAPE = makeCuboidShape(1, 0, 1, 15, 15, 15); + + public BlockAuraTimer() { + super("aura_timer", TileEntityAuraTimer::new, Properties.from(Blocks.SMOOTH_STONE)); + this.setDefaultState(this.getDefaultState().with(BlockStateProperties.POWERED, false)); + } + + @Override + public void generateCustomBlockState(BlockStateGenerator generator) { + generator.simpleBlock(this, generator.models().getExistingFile(generator.modLoc(this.getBaseName()))); + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + return SHAPE; + } + + @Override + @OnlyIn(Dist.CLIENT) + public Tuple, Supplier>>> getTESR() { + return new Tuple<>(ModTileEntities.AURA_TIMER, () -> RenderAuraTimer::new); + } + + @Override + public Supplier getRenderType() { + return RenderType::cutout; + } + + @Override + protected void fillStateContainer(StateContainer.Builder builder) { + builder.add(BlockStateProperties.POWERED); + } + + @Override + public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult p_225533_6_) { + return Helper.putStackOnTile(player, handIn, pos, 0, true); + } + + @Override + public boolean canProvidePower(BlockState state) { + return true; + } + + @Override + public int getWeakPower(BlockState state, IBlockReader world, BlockPos pos, Direction side) { + return state.get(BlockStateProperties.POWERED) ? 15 : 0; + } + + @Override + public int tickRate(IWorldReader world) { + return 4; + } + + @Override + public void tick(BlockState state, ServerWorld worldIn, BlockPos pos, Random random) { + super.tick(state, worldIn, pos, random); + if (state.get(BlockStateProperties.POWERED)) + worldIn.setBlockState(pos, state.with(BlockStateProperties.POWERED, false)); + } + +} diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java b/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java index b3966aba..93bddd0d 100644 --- a/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java +++ b/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java @@ -69,6 +69,7 @@ public final class ModBlocks { public static Block NETHER_GRASS; public static Block LIGHT; public static Block CHORUS_GENERATOR; + public static Block AURA_TIMER; public static Block.Properties prop(Material material, MaterialColor color) { return Block.Properties.create(material, color); diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/tiles/ModTileEntities.java b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/ModTileEntities.java index e4b6f5d9..0b7b3131 100644 --- a/src/main/java/de/ellpeck/naturesaura/blocks/tiles/ModTileEntities.java +++ b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/ModTileEntities.java @@ -39,4 +39,5 @@ public final class ModTileEntities { public static TileEntityType AURA_BLOOM; public static TileEntityType AURA_CACTUS; public static TileEntityType CHORUS_GENERATOR; + public static TileEntityType AURA_TIMER; } diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/tiles/TileEntityAuraTimer.java b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/TileEntityAuraTimer.java new file mode 100644 index 00000000..2d681d66 --- /dev/null +++ b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/TileEntityAuraTimer.java @@ -0,0 +1,125 @@ +package de.ellpeck.naturesaura.blocks.tiles; + +import com.google.common.collect.ImmutableMap; +import de.ellpeck.naturesaura.api.NaturesAuraAPI; +import de.ellpeck.naturesaura.api.aura.type.IAuraType; +import de.ellpeck.naturesaura.items.ItemAuraBottle; +import de.ellpeck.naturesaura.items.ModItems; +import de.ellpeck.naturesaura.packet.PacketHandler; +import de.ellpeck.naturesaura.packet.PacketParticles; +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.items.IItemHandlerModifiable; + +import java.util.Map; + +public class TileEntityAuraTimer extends TileEntityImpl implements ITickableTileEntity { + + private static final Map TIMES = ImmutableMap.builder() + .put(NaturesAuraAPI.TYPE_OVERWORLD, 20) + .put(NaturesAuraAPI.TYPE_NETHER, 20 * 60) + .put(NaturesAuraAPI.TYPE_END, 20 * 60 * 60).build(); + private final ItemStackHandlerNA itemHandler = new ItemStackHandlerNA(1, this, true) { + @Override + protected boolean canInsert(ItemStack stack, int slot) { + return stack.getItem() == ModItems.AURA_BOTTLE; + } + }; + private int timer; + + public TileEntityAuraTimer() { + super(ModTileEntities.AURA_TIMER); + } + + @Override + public void onRedstonePowerChange(int newPower) { + if (this.redstonePower <= 0 && newPower > 0) { + this.timer = 0; + int color = ItemAuraBottle.getType(this.itemHandler.getStackInSlot(0)).getColor(); + PacketHandler.sendToAllAround(this.world, this.pos, 32, new PacketParticles(this.pos.getX(), this.pos.getY(), this.pos.getZ(), PacketParticles.Type.TIMER_RESET, color)); + this.sendToClients(); + } + super.onRedstonePowerChange(newPower); + } + + @Override + public void tick() { + int total = this.getTotalTime(); + if (total <= 0) { + this.timer = 0; + return; + } + + if (this.world.isRemote) { + if (this.world.getGameTime() % 8 == 0) { + int color = ItemAuraBottle.getType(this.itemHandler.getStackInSlot(0)).getColor(); + NaturesAuraAPI.instance().spawnMagicParticle( + this.pos.getX() + 1 / 16F + this.world.rand.nextFloat() * 14 / 16F, + this.pos.getY() + 1 / 16F + this.world.rand.nextFloat() * 14 / 16F, + this.pos.getZ() + 1 / 16F + this.world.rand.nextFloat() * 14 / 16F, + 0, 0, 0, color, 1, 80 + this.world.rand.nextInt(50), 0, false, true); + } + return; + } + + this.timer++; + if (this.timer >= total) { + this.timer = 0; + + BlockState state = this.getBlockState(); + this.world.setBlockState(this.pos, state.with(BlockStateProperties.POWERED, true), 1); + this.world.getPendingBlockTicks().scheduleTick(this.pos, state.getBlock(), state.getBlock().tickRate(this.world)); + + int color = ItemAuraBottle.getType(this.itemHandler.getStackInSlot(0)).getColor(); + PacketHandler.sendToAllAround(this.world, this.pos, 32, new PacketParticles(this.pos.getX(), this.pos.getY(), this.pos.getZ(), PacketParticles.Type.TIMER_RESET, color)); + } + if (this.timer % 2 == 0) + this.sendToClients(); + } + + public int getTotalTime() { + ItemStack stack = this.itemHandler.getStackInSlot(0); + if (stack.isEmpty()) + return 0; + Integer amount = TIMES.get(ItemAuraBottle.getType(stack)); + if (amount == null) + return 0; + return amount * stack.getCount(); + } + + public int getTimeLeft() { + return this.getTotalTime() - this.timer; + } + + public float getTimerPercentage() { + return this.timer / (float) this.getTotalTime(); + } + + @Override + public IItemHandlerModifiable getItemHandler(Direction facing) { + return this.itemHandler; + } + + @Override + public void writeNBT(CompoundNBT compound, SaveType type) { + super.writeNBT(compound, type); + if (type != SaveType.BLOCK) { + compound.put("items", this.itemHandler.serializeNBT()); + compound.putInt("timer", this.timer); + } + } + + @Override + public void readNBT(CompoundNBT compound, SaveType type) { + super.readNBT(compound, type); + if (type != SaveType.BLOCK) { + this.itemHandler.deserializeNBT(compound.getCompound("items")); + this.timer = compound.getInt("timer"); + } + } +} diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/tiles/render/RenderAuraTimer.java b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/render/RenderAuraTimer.java new file mode 100644 index 00000000..9d4b6650 --- /dev/null +++ b/src/main/java/de/ellpeck/naturesaura/blocks/tiles/render/RenderAuraTimer.java @@ -0,0 +1,63 @@ +package de.ellpeck.naturesaura.blocks.tiles.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import de.ellpeck.naturesaura.NaturesAura; +import de.ellpeck.naturesaura.api.aura.type.IAuraType; +import de.ellpeck.naturesaura.blocks.tiles.TileEntityAuraTimer; +import de.ellpeck.naturesaura.items.ItemAuraBottle; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.model.Model; +import net.minecraft.client.renderer.model.ModelRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class RenderAuraTimer extends TileEntityRenderer { + private static final ResourceLocation RES = new ResourceLocation(NaturesAura.MOD_ID, "textures/models/aura_timer_aura.png"); + private final AuraModel model = new AuraModel(); + + public RenderAuraTimer(TileEntityRendererDispatcher disp) { + super(disp); + } + + @Override + public void render(TileEntityAuraTimer tile, float partialTicks, MatrixStack stack, IRenderTypeBuffer buffer, int combinedLightIn, int combinedOverlayIn) { + ItemStack bottle = tile.getItemHandler(null).getStackInSlot(0); + if (bottle.isEmpty()) + return; + stack.push(); + stack.translate(4 / 16F, 2.001F / 16, 4 / 16F); + + float percentage = 1 - tile.getTimerPercentage(); + stack.scale(8 / 16F, 6.5F / 16 * percentage, 8 / 16F); + + IAuraType type = ItemAuraBottle.getType(bottle); + float r = (type.getColor() >> 16 & 255) / 255F; + float g = (type.getColor() >> 8 & 255) / 255F; + float b = (type.getColor() & 255) / 255F; + this.model.render(stack, buffer.getBuffer(this.model.getRenderType(RES)), combinedLightIn, combinedOverlayIn, r, g, b, 0.75F); + stack.pop(); + } + + private static class AuraModel extends Model { + + private final ModelRenderer box; + + public AuraModel() { + super(RenderType::entityTranslucent); + this.box = new ModelRenderer(this, 0, 0); + this.box.setTextureSize(64, 64); + this.box.addBox(0, 0, 0, 16, 16, 16); + } + + @Override + public void render(MatrixStack matrixStackIn, IVertexBuilder bufferIn, int packedLightIn, int packedOverlayIn, float red, float green, float blue, float alpha) { + this.box.render(matrixStackIn, bufferIn, packedLightIn, packedOverlayIn, red, green, blue, alpha); + } + } +} diff --git a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java index f48d5a41..e9e1aa09 100644 --- a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java +++ b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java @@ -10,11 +10,9 @@ import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk; import de.ellpeck.naturesaura.api.aura.container.IAuraContainer; import de.ellpeck.naturesaura.api.aura.type.IAuraType; import de.ellpeck.naturesaura.api.render.IVisualizable; -import de.ellpeck.naturesaura.blocks.tiles.TileEntityGratedChute; -import de.ellpeck.naturesaura.blocks.tiles.TileEntityItemDistributor; -import de.ellpeck.naturesaura.blocks.tiles.TileEntityNatureAltar; -import de.ellpeck.naturesaura.blocks.tiles.TileEntityRFConverter; +import de.ellpeck.naturesaura.blocks.tiles.*; import de.ellpeck.naturesaura.enchant.ModEnchantment; +import de.ellpeck.naturesaura.items.ItemAuraBottle; import de.ellpeck.naturesaura.items.ItemAuraCache; import de.ellpeck.naturesaura.items.ItemRangeVisualizer; import de.ellpeck.naturesaura.items.ModItems; @@ -58,10 +56,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.lwjgl.opengl.GL11; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @OnlyIn(Dist.CLIENT) public class ClientEvents { @@ -446,6 +441,14 @@ public class ClientEvents { GlStateManager.disableDepthTest(); AbstractGui.blit(x - 18, y - 18, u, 0, 16, 16, 256, 256); GlStateManager.enableDepthTest(); + } else if (tile instanceof TileEntityAuraTimer) { + TileEntityAuraTimer timer = (TileEntityAuraTimer) tile; + ItemStack stack = timer.getItemHandler(null).getStackInSlot(0); + if (!stack.isEmpty()) { + Helper.renderItemInGui(stack, x - 20, y - 20, 1); + mc.fontRenderer.drawStringWithShadow(TextFormatting.GRAY + this.createTimeString(timer.getTotalTime()), x + 5, y - 11, 0xFFFFFF); + mc.fontRenderer.drawStringWithShadow(TextFormatting.GRAY + I18n.format("info.naturesaura.remaining", this.createTimeString(timer.getTimeLeft())), x + 5, y + 3, 0xFFFFFF); + } } } } @@ -457,6 +460,14 @@ public class ClientEvents { } } + private String createTimeString(int totalTicks) { + int ticks = totalTicks % 20; + int seconds = totalTicks / 20 % 60; + int minutes = totalTicks / 20 / 60 % 60; + int hours = totalTicks / 20 / 60 / 60; + return String.format("%02d:%02d:%02d.%02d", hours, minutes, seconds, ticks); + } + private void drawContainerInfo(int stored, int max, int color, Minecraft mc, MainWindow res, int yOffset, String name, String textBelow) { RenderSystem.color3f((color >> 16 & 255) / 255F, (color >> 8 & 255) / 255F, (color & 255) / 255F); diff --git a/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java b/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java index 2519d2f0..4fcac6c5 100644 --- a/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java +++ b/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java @@ -504,6 +504,15 @@ public class PacketParticles { world.rand.nextFloat() * 0.04F + 0.02F, world.rand.nextGaussian() * 0.01F, IAuraType.forWorld(world).getColor(), 1F + world.rand.nextFloat() * 1.5F, 40, 0F, false, true); + }), + TIMER_RESET((message, world) -> { + int color = message.data[0]; + for (int i = world.rand.nextInt(10) + 15; i >= 0; i--) + NaturesAuraAPI.instance().spawnMagicParticle( + message.posX + 5 / 16F + world.rand.nextFloat() * 6 / 16F, + message.posY + 2 / 16F + world.rand.nextFloat() * 8 / 16F, + message.posZ + 5 / 16F + world.rand.nextFloat() * 6 / 16F, + 0, 0, 0, color, 2, 40 + world.rand.nextInt(20), 0, false, true); }); public final BiConsumer action; diff --git a/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java b/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java index 0ba85e21..15e20c6b 100644 --- a/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java +++ b/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java @@ -137,7 +137,8 @@ public final class ModRegistry { new BlockImpl("tainted_gold_block", ModBlocks.prop(Material.IRON).sound(SoundType.METAL).hardnessAndResistance(3F)), new BlockNetherGrass(), new BlockLight(), - new BlockChorusGenerator() + new BlockChorusGenerator(), + new BlockAuraTimer() ); if (ModConfig.instance.rfConverter.get()) diff --git a/src/main/resources/assets/naturesaura/lang/en_us.json b/src/main/resources/assets/naturesaura/lang/en_us.json index 552223d0..d715cbe3 100644 --- a/src/main/resources/assets/naturesaura/lang/en_us.json +++ b/src/main/resources/assets/naturesaura/lang/en_us.json @@ -137,6 +137,7 @@ "info.naturesaura.range_visualizer.start": "You take note of the magnification...", "info.naturesaura.range_visualizer.end": "You lose focus of the magnification...", "info.naturesaura.range_visualizer.end_all": "You lose focus of all magnifications...", + "info.naturesaura.remaining": "%s remaining", "advancement.naturesaura.root": "Nature's Aura", "advancement.naturesaura.root.desc": "Becoming a magical botanist", "advancement.naturesaura.get_book": "Pages of Discovery", diff --git a/src/main/resources/assets/naturesaura/models/block/aura_timer.json b/src/main/resources/assets/naturesaura/models/block/aura_timer.json new file mode 100644 index 00000000..689caf85 --- /dev/null +++ b/src/main/resources/assets/naturesaura/models/block/aura_timer.json @@ -0,0 +1,145 @@ +{ + "credit": "Made with Blockbench", + "parent": "minecraft:block/block", + "textures": { + "0": "naturesaura:block/aura_timer_base", + "1": "naturesaura:block/aura_timer_glass_top", + "2": "naturesaura:block/infused_iron_block", + "particle": "naturesaura:block/aura_timer_base" + }, + "elements": [ + { + "name": "base", + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 0, 16, 1], "texture": "#0"}, + "east": {"uv": [0, 0, 16, 1], "texture": "#0"}, + "south": {"uv": [0, 0, 16, 1], "texture": "#0"}, + "west": {"uv": [0, 0, 16, 1], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + }, + { + "from": [2, 14, 2], + "to": [14, 15, 14], + "faces": { + "up": {"uv": [2, 2, 14, 14], "texture": "#1"}, + "down": {"uv": [2, 2, 14, 14], "texture": "#1"} + } + }, + { + "from": [2, 1, 1], + "to": [14, 15, 2], + "faces": { + "north": {"uv": [2, 1, 14, 15], "texture": "#1"}, + "east": {"uv": [2, 1, 3, 15], "texture": "#1"}, + "west": {"uv": [2, 1, 3, 15], "texture": "#1"}, + "up": {"uv": [2, 1, 14, 2], "texture": "#1"} + } + }, + { + "from": [2, 1, 14], + "to": [14, 15, 15], + "faces": { + "east": {"uv": [2, 1, 3, 15], "texture": "#1"}, + "south": {"uv": [2, 1, 14, 15], "texture": "#1"}, + "west": {"uv": [2, 1, 3, 15], "texture": "#1"}, + "up": {"uv": [2, 1, 14, 2], "texture": "#1"} + } + }, + { + "from": [1, 1, 1], + "to": [2, 15, 15], + "faces": { + "north": {"uv": [1, 1, 2, 15], "texture": "#1"}, + "south": {"uv": [1, 1, 2, 15], "texture": "#1"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#1"}, + "up": {"uv": [1, 1, 2, 15], "texture": "#1"} + } + }, + { + "from": [14, 1, 1], + "to": [15, 15, 15], + "faces": { + "north": {"uv": [1, 1, 2, 15], "texture": "#1"}, + "east": {"uv": [1, 1, 15, 15], "texture": "#1"}, + "south": {"uv": [1, 1, 2, 15], "texture": "#1"}, + "up": {"uv": [1, 1, 2, 15], "texture": "#1"} + } + }, + { + "from": [4, 1, 4], + "to": [12, 2, 12], + "faces": { + "north": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "up": {"uv": [1, 1, 9, 9], "texture": "#2"}, + "down": {"uv": [1, 1, 9, 9], "texture": "#2"} + } + }, + { + "from": [3, 2, 4], + "to": [4, 9, 12], + "faces": { + "north": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "east": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "west": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#2"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#2"} + } + }, + { + "from": [12, 2, 4], + "to": [13, 9, 12], + "faces": { + "north": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "east": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "south": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "west": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#2"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#2"} + } + }, + { + "from": [4, 2, 3], + "to": [12, 9, 4], + "faces": { + "north": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "south": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "down": {"uv": [0, 0, 8, 1], "texture": "#2"} + } + }, + { + "from": [4, 2, 12], + "to": [12, 9, 13], + "faces": { + "north": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "south": {"uv": [1, 1, 9, 8], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 7], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 1], "texture": "#2"}, + "down": {"uv": [0, 0, 8, 1], "texture": "#2"} + } + } + ], + "groups": [0, + { + "name": "glass", + "origin": [8, 8, 8], + "children": [1, 2, 3, 4, 5] + }, + { + "name": "bowl", + "origin": [8, 8, 8], + "children": [6, 7, 8, 9, 10] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/naturesaura/textures/block/aura_timer_base.png b/src/main/resources/assets/naturesaura/textures/block/aura_timer_base.png new file mode 100644 index 00000000..149ceb62 Binary files /dev/null and b/src/main/resources/assets/naturesaura/textures/block/aura_timer_base.png differ diff --git a/src/main/resources/assets/naturesaura/textures/block/aura_timer_glass_top.png b/src/main/resources/assets/naturesaura/textures/block/aura_timer_glass_top.png new file mode 100644 index 00000000..fc88072b Binary files /dev/null and b/src/main/resources/assets/naturesaura/textures/block/aura_timer_glass_top.png differ diff --git a/src/main/resources/assets/naturesaura/textures/models/aura_timer_aura.png b/src/main/resources/assets/naturesaura/textures/models/aura_timer_aura.png new file mode 100644 index 00000000..f8862138 Binary files /dev/null and b/src/main/resources/assets/naturesaura/textures/models/aura_timer_aura.png differ