diff --git a/src/main/java/com/minelittlepony/unicopia/block/SpectralFireBlock.java b/src/main/java/com/minelittlepony/unicopia/block/SpectralFireBlock.java new file mode 100644 index 00000000..b9bbd104 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/block/SpectralFireBlock.java @@ -0,0 +1,22 @@ +package com.minelittlepony.unicopia.block; + +import net.minecraft.block.BlockState; +import net.minecraft.block.SoulFireBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SpectralFireBlock extends SoulFireBlock { + + public SpectralFireBlock(Settings settings) { + super(settings); + } + + @Override + public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { + if (!(entity instanceof ItemEntity)) { + super.onEntityCollision(state, world, pos, entity); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java index 02ddcdb6..7611e7b1 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java +++ b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java @@ -225,6 +225,8 @@ public interface UBlocks { Block CRYSTAL_DOOR = register("crystal_door", new CrystalDoorBlock(Settings.copy(Blocks.IRON_DOOR), UWoodTypes.CRYSTAL), ItemGroups.FUNCTIONAL); Block CLOUD_DOOR = register("cloud_door", new CloudDoorBlock(Settings.copy(CLOUD), CLOUD.getDefaultState(), UWoodTypes.CLOUD), ItemGroups.FUNCTIONAL); + Block SPECTRAL_FIRE = register("spectral_fire", new SpectralFireBlock(Settings.copy(Blocks.SOUL_FIRE))); + EdibleBlock HAY_BLOCK = register("hay_block", new EdibleBlock(new Identifier("hay_block"), new Identifier("wheat"), true)); private static T register(String name, T item) { @@ -266,7 +268,7 @@ public interface UBlocks { StrippableBlockRegistry.register(PALM_LOG, STRIPPED_PALM_LOG); StrippableBlockRegistry.register(ZAP_WOOD, STRIPPED_ZAP_WOOD); StrippableBlockRegistry.register(PALM_WOOD, STRIPPED_PALM_WOOD); - Collections.addAll(TRANSLUCENT_BLOCKS, WEATHER_VANE, CHITIN_SPIKES, PLUNDER_VINE, PLUNDER_VINE_BUD, CLAM_SHELL, SCALLOP_SHELL, TURRET_SHELL, CURING_JOKE); + Collections.addAll(TRANSLUCENT_BLOCKS, WEATHER_VANE, CHITIN_SPIKES, PLUNDER_VINE, PLUNDER_VINE_BUD, CLAM_SHELL, SCALLOP_SHELL, TURRET_SHELL, CURING_JOKE, SPECTRAL_FIRE); TintedBlock.REGISTRY.add(PALM_LEAVES); FlammableBlockRegistry.getDefaultInstance().add(GREEN_APPLE_LEAVES, 30, 60); diff --git a/src/main/java/com/minelittlepony/unicopia/block/state/Schematic.java b/src/main/java/com/minelittlepony/unicopia/block/state/Schematic.java index 2053b372..ec6bc112 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/state/Schematic.java +++ b/src/main/java/com/minelittlepony/unicopia/block/state/Schematic.java @@ -9,6 +9,19 @@ import net.minecraft.block.Blocks; import net.minecraft.network.PacketByteBuf; public record Schematic(int dx, int dy, int dz, Entry[] states) { + public static final Schematic ALTAR = new Schematic.Builder() + .fill(0, 0, 0, 8, 0, 8, Blocks.SOUL_SAND.getDefaultState()) + .fill(3, 1, 3, 5, 1, 5, Blocks.OBSIDIAN.getDefaultState()) + .set(4, 1, 4, Blocks.SOUL_SAND.getDefaultState()) + .set(4, 2, 4, Blocks.SOUL_FIRE.getDefaultState()) + .set(4, 1, 6, Blocks.LODESTONE.getDefaultState()) + .fill(0, 1, 2, 0, 4, 2, Blocks.OBSIDIAN.getDefaultState()).fill(0, 1, 6, 0, 4, 6, Blocks.OBSIDIAN.getDefaultState()) + .fill(2, 1, 0, 2, 4, 0, Blocks.OBSIDIAN.getDefaultState()).fill(6, 1, 0, 6, 4, 0, Blocks.OBSIDIAN.getDefaultState()) + .fill(8, 1, 2, 8, 4, 2, Blocks.OBSIDIAN.getDefaultState()).fill(8, 1, 6, 8, 4, 6, Blocks.OBSIDIAN.getDefaultState()) + .fill(2, 1, 8, 2, 4, 8, Blocks.OBSIDIAN.getDefaultState()).fill(6, 1, 8, 6, 4, 8, Blocks.OBSIDIAN.getDefaultState()) + .build(); + + public static Schematic fromPacket(PacketByteBuf buffer) { Builder builder = new Builder(); buffer.readCollection(ArrayList::new, buf -> { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java index ceac4e95..20eb720a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java @@ -81,7 +81,7 @@ public class SpellbookEntityRenderer extends LivingEntityRenderer { - registry.addRecipe(new EmiWorldInteractionRecipe(EmiWorldInteractionRecipe.builder() - .id(recipe.getId()) - .leftInput(EmiStack.of(recipe.getTargetAsItem())) - .rightInput(EmiStack.of(recipe.getCatalyst(), TransformCropsRecipe.MINIMUM_INPUT), true) - .output(EmiStack.of(recipe.getOutput()))) { - @Override - public EmiRecipeCategory getCategory() { - return GROWING_CATEGORY; - } - }); + registry.addRecipe(new StructureInteractionEmiRecipe( + GROWING_CATEGORY, + recipe.getId(), + new Schematic.Builder() + .fill(0, 0, 0, 6, 0, 6, Block.getBlockFromItem(recipe.getCatalyst().getItem()).getDefaultState()) + .set(3, 0, 3, Blocks.FARMLAND.getDefaultState()) + .set(3, 1, 3, Block.getBlockFromItem(recipe.getTargetAsItem().getItem()).getDefaultState()) + .build(), + List.of(EmiStack.of(recipe.getTargetAsItem()), EmiStack.of(recipe.getCatalyst(), TransformCropsRecipe.AREA)), + EmiStack.of(recipe.getOutput()), + Unicopia.id("textures/gui/ability/grow.png") + )); }); + + registry.addCategory(ALTAR_CATEGORY); + registry.addWorkstation(ALTAR_CATEGORY, ALTAR_STATION); + registry.addRecipe(new StructureInteractionEmiRecipe( + ALTAR_CATEGORY, + Unicopia.id("altar/spectral_clock"), + Schematic.ALTAR, + List.of( + EmiStack.of(Items.CLOCK), + EmiStack.of(UItems.SPELLBOOK), + EmiStack.of(Blocks.SOUL_SAND), + EmiStack.of(Blocks.LODESTONE), + EmiStack.of(Blocks.OBSIDIAN, 8 * 4 + 8) + ), + EmiStack.of(UItems.SPECTRAL_CLOCK), + Unicopia.id("textures/gui/race/alicorn.png") + )); } } diff --git a/src/main/java/com/minelittlepony/unicopia/compat/emi/SpellbookEmiRecipe.java b/src/main/java/com/minelittlepony/unicopia/compat/emi/SpellbookEmiRecipe.java index 66329472..1b1caa4b 100644 --- a/src/main/java/com/minelittlepony/unicopia/compat/emi/SpellbookEmiRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/compat/emi/SpellbookEmiRecipe.java @@ -57,36 +57,38 @@ class SpellbookEmiRecipe implements EmiRecipe, SpellbookRecipe.CraftingTreeBuild @Override public int getDisplayWidth() { - return 220; + return 150; } @Override public int getDisplayHeight() { - return 145; + return 75; } @Override public void addWidgets(WidgetHolder widgets) { widgets.addTexture(SpellbookScreen.TEXTURE, 0, 0, getDisplayWidth(), getDisplayHeight(), 50, 50, 128, 128, 512, 256); - widgets.addTexture(Main.EMPTY_ARROW, 160, 65); + widgets.addTexture(Main.EMPTY_ARROW, 85, 30); List grid = new ArrayList<>(); List gem = new ArrayList<>(); - HexagonalCraftingGrid.create(4, 35, 3, grid, gem); + HexagonalCraftingGrid.create(-34, -5, 3, grid, gem); int currentInput = 1; for (int i = 0; i < grid.size(); i++) { - widgets.add(new SlotTexture(grid.get(i))); + var slot = grid.get(i); - if (currentInput < inputs.size() && grid.get(i).weight() == 1) { - widgets.addSlot(inputs.get(currentInput++), grid.get(i).left(), grid.get(i).top()).drawBack(false); - } else { - widgets.addSlot(grid.get(i).left(), grid.get(i).top()).drawBack(false); + if (currentInput < inputs.size() && slot.weight() == 1) { + widgets.add(new SlotTexture(slot)); + widgets.addSlot(inputs.get(currentInput++), slot.left(), slot.top()).drawBack(false); + } else if (slot.weight() == 1) { + widgets.add(new SlotTexture(slot)); + widgets.addSlot(slot.left(), slot.top()).drawBack(false); } } widgets.addSlot(inputs.get(0), gem.get(0).left(), gem.get(0).top()).drawBack(false); - widgets.addSlot(getOutput(), 190, 60).large(true).recipeContext(this); + widgets.addSlot(getOutput(), 120, 25).large(true).recipeContext(this); } protected EmiIngredient getOutput() { diff --git a/src/main/java/com/minelittlepony/unicopia/compat/emi/StructureInteractionEmiRecipe.java b/src/main/java/com/minelittlepony/unicopia/compat/emi/StructureInteractionEmiRecipe.java new file mode 100644 index 00000000..c131aa32 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/compat/emi/StructureInteractionEmiRecipe.java @@ -0,0 +1,144 @@ +package com.minelittlepony.unicopia.compat.emi; + +import java.util.List; + +import com.minelittlepony.unicopia.block.state.Schematic; +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.render.DiffuseLighting; +import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.VertexConsumerProvider.Immediate; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; +import net.minecraft.util.math.RotationAxis; + +public class StructureInteractionEmiRecipe implements EmiRecipe { + + private final EmiRecipeCategory category; + private final Identifier id; + private final Schematic schematic; + + private final List inputs; + private final List output; + + private final Identifier processIcon; + + private int age; + + public StructureInteractionEmiRecipe(EmiRecipeCategory category, Identifier id, Schematic schematic, List inputs, EmiStack output, Identifier processIcon) { + this.category = category; + this.id = id; + this.schematic = schematic; + this.inputs = inputs; + this.output = List.of(output); + this.processIcon = processIcon; + } + + @Override + public EmiRecipeCategory getCategory() { + return category; + } + + @Override + public Identifier getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return output; + } + + @Override + public int getDisplayWidth() { + return 130; + } + + @Override + public int getDisplayHeight() { + return schematic.dy() * 8 + 80 + 20 * (inputs.size() - 2); + } + + @Override + public void addWidgets(WidgetHolder widgets) { + int y = schematic.dy() * 8; + int row = 0; + age = 0; + widgets.addDrawable(10, y / 2, 100, 100, this::renderSchematic); + int x = 10; + for (int i = 0; i < inputs.size(); i++) { + if (i > 1) { + x -= 40; + row += 20; + } + if (i > 0) { + widgets.addTexture(EmiTexture.PLUS, x + 3, y + 53 + row); + x += 20; + } + widgets.addSlot(inputs.get(i), x, y + 50 + row).catalyst(i > 0); + x += 20; + } + widgets.addTexture(EmiTexture.EMPTY_ARROW, 73, y + 52); + widgets.addSlot(output.get(0), 100, y + 47).large(true).recipeContext(this); + widgets.addTexture(processIcon, 73, y + 45, 13, 13, 0, 0, 16, 16, 16, 16).tooltipText(List.of(Text.translatable( + Util.createTranslationKey("recipe", category.getId()) + "." + "instruction" + ))); + } + + private void renderSchematic(DrawContext context, int mouseX, int mouseY, float delta) { + if (schematic.volume() == 0) { + return; + } + MatrixStack matrices = context.getMatrices(); + Immediate immediate = context.getVertexConsumers(); + + MinecraftClient client = MinecraftClient.getInstance(); + + matrices.push(); + float minSize = (Math.max(schematic.dz(), Math.max(schematic.dx(), schematic.dy())) + 1) * 16; + float scale = 60 / minSize; + matrices.scale(scale, scale, 1); + matrices.translate(95, 40, 100); + matrices.scale(16, -16, 16); + + matrices.peek().getNormalMatrix().scale(1, -1, 1); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(20)); + matrices.peek().getPositionMatrix().rotate(RotationAxis.POSITIVE_Y.rotationDegrees(40)); + matrices.translate( + (-schematic.dx() - 1) / 2F, + (-schematic.dy() - 1) / 2F, + (-schematic.dz() - 1) / 2F + ); + DiffuseLighting.disableGuiDepthLighting(); + + age++; + + for (var entry : schematic.states()) { + int x = entry.x() - schematic.dx() / 2; + int z = entry.z() - schematic.dz() / 2; + int distance = x * x + z * z; + if (age >= distance * 2) { + matrices.push(); + matrices.translate(entry.x(), entry.y(), entry.z()); + client.getBlockRenderManager().renderBlockAsEntity(entry.state(), matrices, immediate, LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV); + matrices.pop(); + } + } + + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java index a09abfc8..da18363f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java @@ -262,7 +262,7 @@ public class SpellbookEntity extends MobEntity implements MagicImmune { return; } - //setBeamTicks(0); + setBeamTicks(0); if (activeRecipe == null) { return; diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Altar.java b/src/main/java/com/minelittlepony/unicopia/server/world/Altar.java index 43f3e8fe..d1acdbcf 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Altar.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Altar.java @@ -7,6 +7,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.entity.mob.FloatingArtefactEntity; import com.minelittlepony.unicopia.entity.mob.SpellbookEntity; import com.minelittlepony.unicopia.entity.mob.UEntities; @@ -133,7 +134,7 @@ public record Altar(BlockPos origin, Set pillars) { } public void generateDecorations(World world) { - world.setBlockState(origin, Blocks.SOUL_FIRE.getDefaultState(), Block.FORCE_STATE | Block.NOTIFY_ALL); + world.setBlockState(origin, UBlocks.SPECTRAL_FIRE.getDefaultState(), Block.FORCE_STATE | Block.NOTIFY_ALL); pillars.forEach(pillar -> { FloatingArtefactEntity artefact = UEntities.FLOATING_ARTEFACT.create(world); artefact.setStack(UItems.ALICORN_BADGE.getDefaultStack()); @@ -160,7 +161,7 @@ public record Altar(BlockPos origin, Set pillars) { } public boolean isValid(World world) { - return checkState(world, origin, Blocks.SOUL_FIRE) + return checkState(world, origin, UBlocks.SPECTRAL_FIRE) && checkState(world, origin.down(), Blocks.SOUL_SAND) && checkSlab(world, origin.down()) && pillars.stream().allMatch(pillar -> diff --git a/src/main/resources/assets/unicopia/blockstates/spectral_fire.json b/src/main/resources/assets/unicopia/blockstates/spectral_fire.json new file mode 100644 index 00000000..bd637a77 --- /dev/null +++ b/src/main/resources/assets/unicopia/blockstates/spectral_fire.json @@ -0,0 +1,90 @@ +{ + "multipart": [ + { + "apply": [ + { + "model": "minecraft:block/soul_fire_floor0" + }, + { + "model": "minecraft:block/soul_fire_floor1" + } + ] + }, + { + "apply": [ + { + "model": "minecraft:block/soul_fire_side0" + }, + { + "model": "minecraft:block/soul_fire_side1" + }, + { + "model": "minecraft:block/soul_fire_side_alt0" + }, + { + "model": "minecraft:block/soul_fire_side_alt1" + } + ] + }, + { + "apply": [ + { + "model": "minecraft:block/soul_fire_side0", + "y": 90 + }, + { + "model": "minecraft:block/soul_fire_side1", + "y": 90 + }, + { + "model": "minecraft:block/soul_fire_side_alt0", + "y": 90 + }, + { + "model": "minecraft:block/soul_fire_side_alt1", + "y": 90 + } + ] + }, + { + "apply": [ + { + "model": "minecraft:block/soul_fire_side0", + "y": 180 + }, + { + "model": "minecraft:block/soul_fire_side1", + "y": 180 + }, + { + "model": "minecraft:block/soul_fire_side_alt0", + "y": 180 + }, + { + "model": "minecraft:block/soul_fire_side_alt1", + "y": 180 + } + ] + }, + { + "apply": [ + { + "model": "minecraft:block/soul_fire_side0", + "y": 270 + }, + { + "model": "minecraft:block/soul_fire_side1", + "y": 270 + }, + { + "model": "minecraft:block/soul_fire_side_alt0", + "y": 270 + }, + { + "model": "minecraft:block/soul_fire_side_alt1", + "y": 270 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index c5345aca..5320797e 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -49,6 +49,9 @@ "emi.category.unicopia.spellbook": "Spellbook", "emi.category.unicopia.cloud_shaping": "Shaping", "emi.category.unicopia.growing": "Growing", + "emi.category.unicopia.altar": "Dark Ritual", + "recipe.unicopia.altar.instruction": "Cast item into flames", + "recipe.unicopia.growing.instruction": "Focus Earth Pony Magic", "item.unicopia.alicorn_badge": "Alicorn Emblem", "item.unicopia.unicorn_badge": "Unicorn Emblem", @@ -222,6 +225,7 @@ "block.unicopia.rocks": "Rocks", "block.unicopia.plunder_vine": "Plunder Vine", "block.unicopia.plunder_vine_bud": "Plunder Vine Bud", + "block.unicopia.spectral_fire": "Spectral Fire", "block.unicopia.bananas": "Bananas", "block.unicopia.zapling": "Zapling", "block.unicopia.zap_log": "Zap Apple Log", diff --git a/src/main/resources/data/minecraft/tags/blocks/fire.json b/src/main/resources/data/minecraft/tags/blocks/fire.json new file mode 100644 index 00000000..9abc7a3b --- /dev/null +++ b/src/main/resources/data/minecraft/tags/blocks/fire.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "unicopia:spectral_fire" + ] +}