diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/TouhouLittleMaid.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/TouhouLittleMaid.java index caa765b46..64f95756c 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/TouhouLittleMaid.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/TouhouLittleMaid.java @@ -1,6 +1,7 @@ package com.github.tartaricacid.touhoulittlemaid; import com.github.tartaricacid.touhoulittlemaid.api.ILittleMaid; +import com.github.tartaricacid.touhoulittlemaid.block.multiblock.MultiBlockManager; import com.github.tartaricacid.touhoulittlemaid.config.Config; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; import com.github.tartaricacid.touhoulittlemaid.init.*; @@ -32,13 +33,16 @@ public TouhouLittleMaid() { InitEntities.SCHEDULES.register(FMLJavaModLoadingContext.get().getModEventBus()); InitEntities.DATA_SERIALIZERS.register(FMLJavaModLoadingContext.get().getModEventBus()); InitBlocks.BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus()); + InitBlocks.TILE_ENTITIES.register(FMLJavaModLoadingContext.get().getModEventBus()); InitItems.ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); InitContainer.CONTAINER_TYPE.register(FMLJavaModLoadingContext.get().getModEventBus()); InitSounds.SOUNDS.register(FMLJavaModLoadingContext.get().getModEventBus()); + InitRecipes.RECIPE_SERIALIZERS.register(FMLJavaModLoadingContext.get().getModEventBus()); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.initConfig()); DeferredWorkQueue.runLater(NetworkHandler::init); EXTENSIONS = AnnotatedInstanceUtil.getModExtensions(); TaskManager.init(); BaubleManager.init(); + MultiBlockManager.init(); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java index 75e5fdf91..5bee27981 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java @@ -1,5 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.api; +import com.github.tartaricacid.touhoulittlemaid.block.multiblock.MultiBlockManager; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; import com.github.tartaricacid.touhoulittlemaid.item.bauble.BaubleManager; @@ -13,10 +14,18 @@ default void bindMaidBauble(BaubleManager manager) { } /** - * 注册女仆的 Task + * 添加女仆的 Task * * @param manager 注册器 */ - default void registerMaidTask(TaskManager manager) { + default void addMaidTask(TaskManager manager) { + } + + /** + * 添加多方块结构 + * + * @param manager 注册器 + */ + default void addMultiBlock(MultiBlockManager manager) { } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IMultiBlock.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IMultiBlock.java new file mode 100644 index 000000000..ebe1ef734 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IMultiBlock.java @@ -0,0 +1,64 @@ +package com.github.tartaricacid.touhoulittlemaid.api.block; + +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraft.world.server.ServerWorld; + +public interface IMultiBlock { + /** + * 触发的构建多方块结构时,点击的方块是否为核心方块 + * + * @param blockState 点击的方块 + * @return 是否为核心方块 + */ + boolean isCoreBlock(BlockState blockState); + + /** + * 触发的构建多方块结构时,朝向是否正确 + * + * @param direction 朝向 + * @return 是否为合法的触发方向 + */ + boolean directionIsSuitable(Direction direction); + + /** + * 获取多方块结构的中心点 + * + * @param direction 朝向 + * @return 多方块结构的中心点 + */ + BlockPos getCenterPos(Direction direction); + + /** + * 获取多方块结构模板 + * + * @param world 世界 + * @param direction 朝向 + * @return 多方块结构模板 + */ + Template getTemplate(ServerWorld world, Direction direction); + + /** + * 是否匹配该多方块结构 + * + * @param world 世界实例 + * @param posStart 起始坐标 + * @param direction 判定匹配时的朝向,用来应用到一些具有方向的多方块结构 + * @param template 结构模板 + * @return 是否匹配 + */ + boolean isMatch(World world, BlockPos posStart, Direction direction, Template template); + + /** + * 修建多方块结构的逻辑 + * + * @param worldIn 世界实例 + * @param posStart 起始坐标 + * @param direction 判定匹配时的朝向,用来应用到一些具有方向的多方块结构 + * @param template 结构模板 + */ + void build(World worldIn, BlockPos posStart, Direction direction, Template template); +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java new file mode 100644 index 000000000..9b4c31145 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java @@ -0,0 +1,298 @@ +package com.github.tartaricacid.touhoulittlemaid.block; + +import com.github.tartaricacid.touhoulittlemaid.capability.PowerCapability; +import com.github.tartaricacid.touhoulittlemaid.capability.PowerCapabilityProvider; +import com.github.tartaricacid.touhoulittlemaid.crafting.AltarRecipe; +import com.github.tartaricacid.touhoulittlemaid.init.InitRecipes; +import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; +import com.github.tartaricacid.touhoulittlemaid.inventory.AltarRecipeInventory; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; +import com.github.tartaricacid.touhoulittlemaid.util.PosListData; +import net.minecraft.block.*; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.DiggingParticle; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.pathfinding.PathType; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.Explosion; +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 net.minecraftforge.items.ItemHandlerHelper; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; + +import static net.minecraftforge.common.util.Constants.BlockFlags.DEFAULT; + +public class BlockAltar extends Block { + public BlockAltar() { + super(AbstractBlock.Properties.of(Material.STONE).strength(2, 2).noOcclusion()); + } + + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Nullable + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new TileEntityAltar(); + } + + @Override + public ActionResultType use(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { + return this.getAltar(worldIn, pos).filter(altar -> handIn == Hand.MAIN_HAND).map(altar -> { + if (player.isShiftKeyDown() || player.getMainHandItem().isEmpty()) { + takeOutItem(worldIn, pos, altar, player); + } else { + takeInOrCraft(worldIn, altar, player); + } + altar.refresh(); + return ActionResultType.sidedSuccess(worldIn.isClientSide); + }).orElse(super.use(state, worldIn, pos, player, handIn, hit)); + } + + @Override + public void onRemove(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (!worldIn.isClientSide) { + this.getAltar(worldIn, pos).ifPresent(altar -> { + ItemStack stack = altar.handler.getStackInSlot(0); + if (!stack.isEmpty()) { + Block.popResource(worldIn, pos.offset(0, 1, 0), stack); + } + }); + } + super.onRemove(state, worldIn, pos, newState, isMoving); + } + + @Override + public void onBlockExploded(BlockState state, World world, BlockPos pos, Explosion explosion) { + if (!world.isClientSide) { + this.getAltar(world, pos).ifPresent(altar -> this.restoreStorageBlock(world, pos, altar.getBlockPosList())); + } + super.onBlockExploded(state, world, pos, explosion); + } + + @Override + public void playerWillDestroy(World worldIn, BlockPos pos, BlockState state, PlayerEntity player) { + if (!worldIn.isClientSide) { + this.getAltar(worldIn, pos).ifPresent(altar -> { + this.restoreStorageBlock(worldIn, pos, altar.getBlockPosList()); + if (!player.isCreative()) { + Block block = altar.getStorageState().getBlock(); + Block.popResource(worldIn, pos, new ItemStack(block)); + } + }); + } + super.playerWillDestroy(worldIn, pos, state, player); + } + + @Override + public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player) { + return this.getAltar(world, pos) + .map(altar -> new ItemStack(altar.getStorageState().getBlock())) + .orElse(super.getPickBlock(state, target, world, pos, player)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public boolean addDestroyEffects(BlockState state, World world, BlockPos pos, ParticleManager manager) { + this.getAltar(world, pos).ifPresent(altar -> Minecraft.getInstance().particleEngine.destroy(pos, altar.getStorageState())); + return true; + } + + @Override + @OnlyIn(Dist.CLIENT) + public boolean addHitEffects(BlockState state, World world, RayTraceResult target, ParticleManager manager) { + if (target instanceof BlockRayTraceResult && world instanceof ClientWorld) { + BlockRayTraceResult blockTarget = (BlockRayTraceResult) target; + BlockPos pos = blockTarget.getBlockPos(); + ClientWorld clientWorld = (ClientWorld) world; + this.getAltar(world, pos).ifPresent(altar -> this.crack(clientWorld, pos, altar.getStorageState(), blockTarget.getDirection())); + } + return true; + } + + @Override + public SoundType getSoundType(BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity entity) { + return this.getAltar(world, pos) + .map(altar -> altar.getStorageState().getSoundType()) + .orElse(super.getSoundType(state, world, pos, entity)); + } + + @Override + public BlockRenderType getRenderShape(BlockState state) { + return BlockRenderType.ENTITYBLOCK_ANIMATED; + } + + @Override + public boolean isPathfindable(BlockState state, IBlockReader worldIn, BlockPos pos, PathType type) { + return false; + } + + private void restoreStorageBlock(World worldIn, BlockPos currentPos, PosListData posList) { + for (BlockPos storagePos : posList.getData()) { + if (storagePos.equals(currentPos)) { + continue; + } + this.getAltar(worldIn, storagePos).ifPresent(altar -> worldIn.setBlock(storagePos, altar.getStorageState(), DEFAULT)); + } + } + + private void takeOutItem(World world, BlockPos pos, TileEntityAltar altar, PlayerEntity player) { + if (altar.isCanPlaceItem()) { + if (!altar.handler.getStackInSlot(0).isEmpty()) { + Block.popResource(world, pos.offset(0, 1, 0), altar.handler.extractItem(0, 1, false)); + altarCraft(world, altar, player); + } + } + } + + private void takeInOrCraft(World world, TileEntityAltar altar, PlayerEntity playerIn) { + if (altar.isCanPlaceItem() && altar.handler.getStackInSlot(0).isEmpty()) { + altar.handler.setStackInSlot(0, ItemHandlerHelper.copyStackWithSize(playerIn.getMainHandItem(), 1)); + if (!playerIn.isCreative()) { + playerIn.getMainHandItem().shrink(1); + } + altarCraft(world, altar, playerIn); + } + } + + private void altarCraft(World world, TileEntityAltar altar, PlayerEntity playerIn) { + final AltarRecipeInventory inv = new AltarRecipeInventory(); + List posList = altar.getCanPlaceItemPosList().getData(); + for (int i = 0; i < posList.size(); i++) { + TileEntity te = world.getBlockEntity(posList.get(i)); + if (te instanceof TileEntityAltar) { + inv.setItem(i, ((TileEntityAltar) te).getStorageItem()); + } + } + if (inv.isEmpty()) { + return; + } + playerIn.getCapability(PowerCapabilityProvider.POWER_CAP, null) + .ifPresent(power -> world.getRecipeManager().getRecipeFor(InitRecipes.ALTAR_CRAFTING, inv, world) + .ifPresent(recipe -> spawnResultEntity(world, playerIn, power, recipe, inv, altar))); + } + + private Optional getAltar(IBlockReader world, BlockPos pos) { + TileEntity te = world.getBlockEntity(pos); + if (te instanceof TileEntityAltar) { + return Optional.of((TileEntityAltar) te); + } + return Optional.empty(); + } + + private void spawnResultEntity(World world, PlayerEntity playerIn, PowerCapability power, + AltarRecipe altarRecipe, AltarRecipeInventory inventory, TileEntityAltar altar) { + if (power.get() >= altarRecipe.getPowerCost()) { + power.min(altarRecipe.getPowerCost()); + BlockPos centrePos = getCentrePos(altar.getBlockPosList(), altar.getBlockPos()); + if (world instanceof ServerWorld) { + altarRecipe.spawnOutputEntity((ServerWorld) world, centrePos, inventory); + } + removeAllAltarItem(world, altar); + spawnParticleInCentre(world, centrePos); + world.playSound(null, centrePos, InitSounds.ALTAR_CRAFT.get(), SoundCategory.VOICE, 1.0f, 1.0f); + } else { + if (!world.isClientSide) { + playerIn.sendMessage(new TranslationTextComponent("message.touhou_little_maid.altar.not_enough_power"), Util.NIL_UUID); + } + } + } + + + @OnlyIn(Dist.CLIENT) + private void crack(ClientWorld world, BlockPos pos, BlockState state, Direction side) { + if (state.getRenderShape() != BlockRenderType.INVISIBLE) { + int posX = pos.getX(); + int posY = pos.getY(); + int posZ = pos.getZ(); + AxisAlignedBB aabb = state.getShape(world, pos).bounds(); + double x = posX + this.RANDOM.nextDouble() * (aabb.maxX - aabb.minX - 0.2) + 0.1 + aabb.minX; + double y = posY + this.RANDOM.nextDouble() * (aabb.maxY - aabb.minY - 0.2) + 0.1 + aabb.minY; + double z = posZ + this.RANDOM.nextDouble() * (aabb.maxZ - aabb.minZ - 0.2) + 0.1 + aabb.minZ; + if (side == Direction.DOWN) { + y = posY + aabb.minY - 0.1; + } + if (side == Direction.UP) { + y = posY + aabb.maxY + 0.1; + } + if (side == Direction.NORTH) { + z = posZ + aabb.minZ - 0.1; + } + if (side == Direction.SOUTH) { + z = posZ + aabb.maxZ + 0.1; + } + if (side == Direction.WEST) { + x = posX + aabb.minX - 0.1; + } + if (side == Direction.EAST) { + x = posX + aabb.maxX + 0.1; + } + DiggingParticle diggingParticle = new DiggingParticle(world, x, y, z, 0, 0, 0, state); + Minecraft.getInstance().particleEngine.add(diggingParticle.init(pos).setPower(0.2f).scale(0.6f)); + } + } + + private BlockPos getCentrePos(PosListData posList, BlockPos posClick) { + int x = 0; + int y = posClick.getY() - 2; + int z = 0; + for (BlockPos pos : posList.getData()) { + if (pos.getY() == y) { + x += pos.getX(); + z += pos.getZ(); + } + } + return new BlockPos(x / 8, y, z / 8); + } + + private void removeAllAltarItem(World world, TileEntityAltar altar) { + for (BlockPos pos : altar.getCanPlaceItemPosList().getData()) { + this.getAltar(world, pos).ifPresent(te -> { + te.handler.setStackInSlot(0, ItemStack.EMPTY); + te.refresh(); + spawnParticleInCentre(world, te.getBlockPos()); + }); + } + } + + private void spawnParticleInCentre(World world, BlockPos centrePos) { + int width = 1; + int height = 1; + for (int i = 0; i < 5; ++i) { + double xSpeed = RANDOM.nextGaussian() * 0.02; + double ySpeed = RANDOM.nextGaussian() * 0.02; + double zSpeed = RANDOM.nextGaussian() * 0.02; + world.addParticle(ParticleTypes.CLOUD, + centrePos.getX() + RANDOM.nextFloat() * width * 2 - width - xSpeed * 10, + centrePos.getY() + RANDOM.nextFloat() * height - ySpeed * 10, + centrePos.getZ() + RANDOM.nextFloat() * width * 2 - width - zSpeed * 10, + xSpeed, ySpeed, zSpeed); + world.addParticle(ParticleTypes.SMOKE, + centrePos.getX() + RANDOM.nextFloat() * width * 2 - width - xSpeed * 10, + centrePos.getY() + RANDOM.nextFloat() * height - ySpeed * 10, + centrePos.getZ() + RANDOM.nextFloat() * width * 2 - width - zSpeed * 10, + xSpeed, ySpeed, zSpeed); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockAltar.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockAltar.java new file mode 100644 index 000000000..580bac3d2 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockAltar.java @@ -0,0 +1,110 @@ +package com.github.tartaricacid.touhoulittlemaid.block.multiblock; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.block.IMultiBlock; +import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; +import com.github.tartaricacid.touhoulittlemaid.util.PosListData; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.Constants; + +public class MultiBlockAltar implements IMultiBlock { + private static final ResourceLocation ALTAR_SOUTH = new ResourceLocation(TouhouLittleMaid.MOD_ID, "altar_south"); + private static final ResourceLocation ALTAR_NORTH = new ResourceLocation(TouhouLittleMaid.MOD_ID, "altar_north"); + private static final ResourceLocation ALTAR_EAST = new ResourceLocation(TouhouLittleMaid.MOD_ID, "altar_east"); + private static final ResourceLocation ALTAR_WEST = new ResourceLocation(TouhouLittleMaid.MOD_ID, "altar_west"); + private static final BlockPos SOUTH_POS = new BlockPos(-4, -3, 0); + private static final BlockPos NORTH_POS = new BlockPos(-3, -3, -7); + private static final BlockPos EAST_POS = new BlockPos(0, -3, -3); + private static final BlockPos WEST_POS = new BlockPos(-7, -3, -4); + + @Override + public boolean isCoreBlock(BlockState blockState) { + return blockState.is(Blocks.RED_WOOL); + } + + @Override + public boolean isMatch(World world, BlockPos posStart, Direction direction, Template template) { + Template.Palette palette = template.palettes.get(0); + for (Template.BlockInfo blockInfo : palette.blocks()) { + if (!world.getBlockState(posStart.offset(blockInfo.pos)).equals(blockInfo.state)) { + return false; + } + } + return true; + } + + @Override + public void build(World worldIn, BlockPos posStart, Direction direction, Template template) { + PosListData posList = new PosListData(); + PosListData canPlaceItemPosList = new PosListData(); + Template.Palette palette = template.palettes.get(0); + + for (Template.BlockInfo blockInfo : palette.blocks()) { + posList.add(posStart.offset(blockInfo.pos)); + if (blockInfo.pos.getY() == 2 && blockInfo.state.is(Blocks.OAK_LOG)) { + canPlaceItemPosList.add(posStart.offset(blockInfo.pos)); + } + } + + BlockPos currentCenterPos = posStart.subtract(getCenterPos(direction)); + for (Template.BlockInfo blockInfo : palette.blocks()) { + BlockPos currentPos = posStart.offset(blockInfo.pos); + worldIn.setBlock(currentPos, InitBlocks.ALTAR.get().defaultBlockState(), Constants.BlockFlags.DEFAULT); + TileEntity te = worldIn.getBlockEntity(currentPos); + if (te instanceof TileEntityAltar) { + boolean isRender = currentPos.equals(currentCenterPos); + boolean canPlaceItem = blockInfo.pos.getY() == 2 && blockInfo.state.is(Blocks.OAK_LOG); + ((TileEntityAltar) te).setForgeData(blockInfo.state, isRender, + canPlaceItem, direction, posList, canPlaceItemPosList); + } + } + } + + @Override + public boolean directionIsSuitable(Direction direction) { + return direction != Direction.DOWN && direction != Direction.UP; + } + + @Override + public BlockPos getCenterPos(Direction facing) { + switch (facing) { + case NORTH: + return SOUTH_POS; + case EAST: + return WEST_POS; + case WEST: + return EAST_POS; + case SOUTH: + default: + return NORTH_POS; + } + } + + @Override + public Template getTemplate(ServerWorld world, Direction facing) { + switch (facing) { + case NORTH: + return getAltarTemplate(world, ALTAR_SOUTH); + case EAST: + return getAltarTemplate(world, ALTAR_WEST); + case WEST: + return getAltarTemplate(world, ALTAR_EAST); + case SOUTH: + default: + return getAltarTemplate(world, ALTAR_NORTH); + } + } + + private Template getAltarTemplate(ServerWorld world, ResourceLocation location) { + return world.getStructureManager().getOrCreate(location); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockManager.java new file mode 100644 index 000000000..7fded3b0b --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/multiblock/MultiBlockManager.java @@ -0,0 +1,34 @@ +package com.github.tartaricacid.touhoulittlemaid.block.multiblock; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.ILittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.block.IMultiBlock; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import java.util.List; + +public final class MultiBlockManager { + private static List MULTI_BLOCK_LIST; + + private MultiBlockManager() { + MULTI_BLOCK_LIST = Lists.newArrayList(); + } + + public static void init() { + MultiBlockManager manager = new MultiBlockManager(); + manager.add(new MultiBlockAltar()); + for (ILittleMaid littleMaid : TouhouLittleMaid.EXTENSIONS) { + littleMaid.addMultiBlock(manager); + } + MULTI_BLOCK_LIST = ImmutableList.copyOf(MULTI_BLOCK_LIST); + } + + public static List getMultiBlockList() { + return MULTI_BLOCK_LIST; + } + + public void add(IMultiBlock multiBlock) { + MULTI_BLOCK_LIST.add(multiBlock); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java index 020304ed9..898a84ad7 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java @@ -1,14 +1,17 @@ package com.github.tartaricacid.touhoulittlemaid.client.init; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.*; +import com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity.TileEntityAltarRenderer; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityChair; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityExtinguishingAgent; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityPowerPoint; import com.github.tartaricacid.touhoulittlemaid.entity.monster.EntityFairy; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.projectile.EntityDanmaku; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -23,5 +26,6 @@ public static void clientSetup(FMLClientSetupEvent evt) { RenderingRegistry.registerEntityRenderingHandler(EntityDanmaku.TYPE, EntityDanmakuRenderer::new); RenderingRegistry.registerEntityRenderingHandler(EntityPowerPoint.TYPE, EntityPowerPointRenderer::new); RenderingRegistry.registerEntityRenderingHandler(EntityExtinguishingAgent.TYPE, EntityExtinguishingAgentRenderer::new); + ClientRegistry.bindTileEntityRenderer(TileEntityAltar.TYPE, TileEntityAltarRenderer::new); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/AltarModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/AltarModel.java new file mode 100644 index 000000000..b2018f6e9 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/AltarModel.java @@ -0,0 +1,642 @@ +package com.github.tartaricacid.touhoulittlemaid.client.model; + + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import net.minecraft.client.renderer.entity.model.EntityModel; +import net.minecraft.client.renderer.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class AltarModel extends EntityModel { + private final ModelRenderer pillar; + private final ModelRenderer bone2; + private final ModelRenderer bone3; + private final ModelRenderer bone4; + private final ModelRenderer bone5; + private final ModelRenderer bone10; + private final ModelRenderer bone6; + private final ModelRenderer bone7; + private final ModelRenderer bone8; + private final ModelRenderer bone9; + private final ModelRenderer pillar2; + private final ModelRenderer bone11; + private final ModelRenderer bone12; + private final ModelRenderer bone13; + private final ModelRenderer bone14; + private final ModelRenderer bone15; + private final ModelRenderer bone16; + private final ModelRenderer bone17; + private final ModelRenderer bone18; + private final ModelRenderer bone19; + private final ModelRenderer pillar3; + private final ModelRenderer bone20; + private final ModelRenderer bone21; + private final ModelRenderer bone22; + private final ModelRenderer bone23; + private final ModelRenderer bone24; + private final ModelRenderer bone25; + private final ModelRenderer bone26; + private final ModelRenderer bone27; + private final ModelRenderer bone28; + private final ModelRenderer pillar4; + private final ModelRenderer bone29; + private final ModelRenderer bone30; + private final ModelRenderer bone31; + private final ModelRenderer bone32; + private final ModelRenderer bone33; + private final ModelRenderer bone34; + private final ModelRenderer bone35; + private final ModelRenderer bone36; + private final ModelRenderer bone37; + private final ModelRenderer pillar5; + private final ModelRenderer bone38; + private final ModelRenderer bone39; + private final ModelRenderer bone40; + private final ModelRenderer bone41; + private final ModelRenderer bone42; + private final ModelRenderer bone43; + private final ModelRenderer bone44; + private final ModelRenderer bone45; + private final ModelRenderer bone46; + private final ModelRenderer pillar6; + private final ModelRenderer bone47; + private final ModelRenderer bone48; + private final ModelRenderer bone49; + private final ModelRenderer bone50; + private final ModelRenderer bone51; + private final ModelRenderer bone52; + private final ModelRenderer bone53; + private final ModelRenderer bone54; + private final ModelRenderer bone55; + private final ModelRenderer bone; + private final ModelRenderer bone56; + private final ModelRenderer bone57; + private final ModelRenderer bone58; + private final ModelRenderer bone59; + private final ModelRenderer bone60; + private final ModelRenderer bone61; + private final ModelRenderer bone63; + private final ModelRenderer bone62; + private final ModelRenderer bone64; + + public AltarModel() { + texWidth = 256; + texHeight = 256; + + pillar = new ModelRenderer(this); + pillar.setPos(0.0F, 24.0F, 0.0F); + pillar.texOffs(0, 44).addBox(48.0F, -48.0F, 16.0F, 16.0F, 48.0F, 16.0F, 0.0F, false); + pillar.texOffs(0, 21).addBox(47.5F, -48.5F, 15.5F, 17.0F, 6.0F, 17.0F, 0.0F, false); + pillar.texOffs(0, 0).addBox(47.5F, -33.5F, 15.5F, 17.0F, 4.0F, 17.0F, 0.0F, false); + + bone2 = new ModelRenderer(this); + bone2.setPos(-4.25F, -27.5F, 14.8F); + pillar.addChild(bone2); + setRotationAngle(bone2, -0.1745F, 0.1745F, 0.7854F); + bone2.texOffs(0, 0).addBox(36.9617F, -42.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone2.texOffs(0, 0).addBox(40.9617F, -38.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone2.texOffs(0, 0).addBox(44.9617F, -34.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone3 = new ModelRenderer(this); + bone3.setPos(4.25F, -27.5F, 14.8F); + pillar.addChild(bone3); + setRotationAngle(bone3, -0.1745F, -0.1745F, -0.7854F); + bone3.texOffs(0, 0).addBox(37.0311F, 38.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone3.texOffs(0, 0).addBox(33.0311F, 42.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone3.texOffs(0, 0).addBox(29.0311F, 46.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone4 = new ModelRenderer(this); + bone4.setPos(-4.25F, -27.5F, 33.2F); + pillar.addChild(bone4); + setRotationAngle(bone4, 0.1745F, -0.1745F, 0.7854F); + bone4.texOffs(0, 0).addBox(36.9964F, -42.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone4.texOffs(0, 0).addBox(40.9964F, -38.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone4.texOffs(0, 0).addBox(44.9964F, -34.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone5 = new ModelRenderer(this); + bone5.setPos(4.25F, -27.5F, 33.2F); + pillar.addChild(bone5); + setRotationAngle(bone5, 0.1745F, 0.1745F, -0.7854F); + bone5.texOffs(0, 0).addBox(36.9964F, 38.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone5.texOffs(0, 0).addBox(32.9964F, 42.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone5.texOffs(0, 0).addBox(28.9964F, 46.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone10 = new ModelRenderer(this); + bone10.setPos(0.0F, 0.0F, 24.0F); + pillar.addChild(bone10); + setRotationAngle(bone10, 0.0F, 1.5708F, 0.0F); + + + bone6 = new ModelRenderer(this); + bone6.setPos(-4.25F, -27.5F, -9.2F); + bone10.addChild(bone6); + setRotationAngle(bone6, -0.1745F, 0.1745F, 0.7854F); + bone6.texOffs(0, 0).addBox(-11.7243F, -11.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone6.texOffs(0, 0).addBox(-7.7243F, -7.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone6.texOffs(0, 0).addBox(-3.7243F, -3.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone7 = new ModelRenderer(this); + bone7.setPos(4.25F, -27.5F, -9.2F); + bone10.addChild(bone7); + setRotationAngle(bone7, -0.1745F, -0.1745F, -0.7854F); + bone7.texOffs(0, 0).addBox(7.7243F, -11.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone7.texOffs(0, 0).addBox(3.7243F, -7.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone7.texOffs(0, 0).addBox(-0.2757F, -3.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone8 = new ModelRenderer(this); + bone8.setPos(-4.25F, -27.5F, 9.2F); + bone10.addChild(bone8); + setRotationAngle(bone8, 0.1745F, -0.1745F, 0.7854F); + bone8.texOffs(0, 0).addBox(7.7243F, 7.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone8.texOffs(0, 0).addBox(11.7243F, 11.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone8.texOffs(0, 0).addBox(15.7243F, 15.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone9 = new ModelRenderer(this); + bone9.setPos(4.25F, -27.5F, 9.2F); + bone10.addChild(bone9); + setRotationAngle(bone9, 0.1745F, 0.1745F, -0.7854F); + bone9.texOffs(0, 0).addBox(-11.7243F, 7.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone9.texOffs(0, 0).addBox(-15.7243F, 11.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone9.texOffs(0, 0).addBox(-19.7243F, 15.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + pillar2 = new ModelRenderer(this); + pillar2.setPos(0.0F, 24.0F, 0.0F); + pillar2.texOffs(0, 44).addBox(48.0F, -48.0F, -32.0F, 16.0F, 48.0F, 16.0F, 0.0F, false); + pillar2.texOffs(0, 21).addBox(47.5F, -48.5F, -32.5F, 17.0F, 6.0F, 17.0F, 0.0F, false); + pillar2.texOffs(0, 0).addBox(47.5F, -33.5F, -32.5F, 17.0F, 4.0F, 17.0F, 0.0F, false); + + bone11 = new ModelRenderer(this); + bone11.setPos(-4.25F, -27.5F, -14.8F); + pillar2.addChild(bone11); + setRotationAngle(bone11, 0.1745F, -0.1745F, 0.7854F); + bone11.texOffs(0, 0).addBox(36.9617F, -42.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone11.texOffs(0, 0).addBox(40.9617F, -38.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone11.texOffs(0, 0).addBox(44.9617F, -34.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone12 = new ModelRenderer(this); + bone12.setPos(4.25F, -27.5F, -14.8F); + pillar2.addChild(bone12); + setRotationAngle(bone12, 0.1745F, 0.1745F, -0.7854F); + bone12.texOffs(0, 0).addBox(37.0311F, 38.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone12.texOffs(0, 0).addBox(33.0311F, 42.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone12.texOffs(0, 0).addBox(29.0311F, 46.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone13 = new ModelRenderer(this); + bone13.setPos(-4.25F, -27.5F, -33.2F); + pillar2.addChild(bone13); + setRotationAngle(bone13, -0.1745F, 0.1745F, 0.7854F); + bone13.texOffs(0, 0).addBox(36.9964F, -42.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone13.texOffs(0, 0).addBox(40.9964F, -38.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone13.texOffs(0, 0).addBox(44.9964F, -34.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone14 = new ModelRenderer(this); + bone14.setPos(4.25F, -27.5F, -33.2F); + pillar2.addChild(bone14); + setRotationAngle(bone14, -0.1745F, -0.1745F, -0.7854F); + bone14.texOffs(0, 0).addBox(36.9964F, 38.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone14.texOffs(0, 0).addBox(32.9964F, 42.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone14.texOffs(0, 0).addBox(28.9964F, 46.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone15 = new ModelRenderer(this); + bone15.setPos(0.0F, 0.0F, -24.0F); + pillar2.addChild(bone15); + setRotationAngle(bone15, 0.0F, -1.5708F, 0.0F); + + + bone16 = new ModelRenderer(this); + bone16.setPos(-4.25F, -27.5F, 9.2F); + bone15.addChild(bone16); + setRotationAngle(bone16, 0.1745F, -0.1745F, 0.7854F); + bone16.texOffs(0, 0).addBox(-11.7243F, -11.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone16.texOffs(0, 0).addBox(-7.7243F, -7.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone16.texOffs(0, 0).addBox(-3.7243F, -3.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone17 = new ModelRenderer(this); + bone17.setPos(4.25F, -27.5F, 9.2F); + bone15.addChild(bone17); + setRotationAngle(bone17, 0.1745F, 0.1745F, -0.7854F); + bone17.texOffs(0, 0).addBox(7.7243F, -11.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone17.texOffs(0, 0).addBox(3.7243F, -7.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone17.texOffs(0, 0).addBox(-0.2757F, -3.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone18 = new ModelRenderer(this); + bone18.setPos(-4.25F, -27.5F, -9.2F); + bone15.addChild(bone18); + setRotationAngle(bone18, -0.1745F, 0.1745F, 0.7854F); + bone18.texOffs(0, 0).addBox(7.7243F, 7.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone18.texOffs(0, 0).addBox(11.7243F, 11.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone18.texOffs(0, 0).addBox(15.7243F, 15.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone19 = new ModelRenderer(this); + bone19.setPos(4.25F, -27.5F, -9.2F); + bone15.addChild(bone19); + setRotationAngle(bone19, -0.1745F, -0.1745F, -0.7854F); + bone19.texOffs(0, 0).addBox(-11.7243F, 7.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone19.texOffs(0, 0).addBox(-15.7243F, 11.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone19.texOffs(0, 0).addBox(-19.7243F, 15.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + pillar3 = new ModelRenderer(this); + pillar3.setPos(0.0F, 24.0F, 0.0F); + pillar3.texOffs(0, 44).addBox(-64.0F, -48.0F, 16.0F, 16.0F, 48.0F, 16.0F, 0.0F, true); + pillar3.texOffs(0, 21).addBox(-64.5F, -48.5F, 15.5F, 17.0F, 6.0F, 17.0F, 0.0F, true); + pillar3.texOffs(0, 0).addBox(-64.5F, -33.5F, 15.5F, 17.0F, 4.0F, 17.0F, 0.0F, true); + + bone20 = new ModelRenderer(this); + bone20.setPos(4.25F, -27.5F, 14.8F); + pillar3.addChild(bone20); + setRotationAngle(bone20, -0.1745F, -0.1745F, -0.7854F); + bone20.texOffs(0, 0).addBox(-40.9617F, -42.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone20.texOffs(0, 0).addBox(-44.9617F, -38.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone20.texOffs(0, 0).addBox(-48.9617F, -34.2246F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone21 = new ModelRenderer(this); + bone21.setPos(-4.25F, -27.5F, 14.8F); + pillar3.addChild(bone21); + setRotationAngle(bone21, -0.1745F, 0.1745F, 0.7854F); + bone21.texOffs(0, 0).addBox(-41.0311F, 38.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone21.texOffs(0, 0).addBox(-37.0311F, 42.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone21.texOffs(0, 0).addBox(-33.0311F, 46.1562F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone22 = new ModelRenderer(this); + bone22.setPos(4.25F, -27.5F, 33.2F); + pillar3.addChild(bone22); + setRotationAngle(bone22, 0.1745F, 0.1745F, -0.7854F); + bone22.texOffs(0, 0).addBox(-40.9964F, -42.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone22.texOffs(0, 0).addBox(-44.9964F, -38.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone22.texOffs(0, 0).addBox(-48.9964F, -34.1904F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone23 = new ModelRenderer(this); + bone23.setPos(-4.25F, -27.5F, 33.2F); + pillar3.addChild(bone23); + setRotationAngle(bone23, 0.1745F, -0.1745F, 0.7854F); + bone23.texOffs(0, 0).addBox(-40.9964F, 38.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone23.texOffs(0, 0).addBox(-36.9964F, 42.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone23.texOffs(0, 0).addBox(-32.9964F, 46.1904F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone24 = new ModelRenderer(this); + bone24.setPos(0.0F, 0.0F, 24.0F); + pillar3.addChild(bone24); + setRotationAngle(bone24, 0.0F, -1.5708F, 0.0F); + + + bone25 = new ModelRenderer(this); + bone25.setPos(4.25F, -27.5F, -9.2F); + bone24.addChild(bone25); + setRotationAngle(bone25, -0.1745F, -0.1745F, -0.7854F); + bone25.texOffs(0, 0).addBox(7.7243F, -11.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone25.texOffs(0, 0).addBox(3.7243F, -7.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone25.texOffs(0, 0).addBox(-0.2757F, -3.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone26 = new ModelRenderer(this); + bone26.setPos(-4.25F, -27.5F, -9.2F); + bone24.addChild(bone26); + setRotationAngle(bone26, -0.1745F, 0.1745F, 0.7854F); + bone26.texOffs(0, 0).addBox(-11.7243F, -11.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone26.texOffs(0, 0).addBox(-7.7243F, -7.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone26.texOffs(0, 0).addBox(-3.7243F, -3.5766F, 54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone27 = new ModelRenderer(this); + bone27.setPos(4.25F, -27.5F, 9.2F); + bone24.addChild(bone27); + setRotationAngle(bone27, 0.1745F, 0.1745F, -0.7854F); + bone27.texOffs(0, 0).addBox(-11.7243F, 7.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone27.texOffs(0, 0).addBox(-15.7243F, 11.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone27.texOffs(0, 0).addBox(-19.7243F, 15.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone28 = new ModelRenderer(this); + bone28.setPos(-4.25F, -27.5F, 9.2F); + bone24.addChild(bone28); + setRotationAngle(bone28, 0.1745F, -0.1745F, 0.7854F); + bone28.texOffs(0, 0).addBox(7.7243F, 7.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone28.texOffs(0, 0).addBox(11.7243F, 11.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone28.texOffs(0, 0).addBox(15.7243F, 15.5766F, 54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + pillar4 = new ModelRenderer(this); + pillar4.setPos(0.0F, 24.0F, 0.0F); + pillar4.texOffs(0, 44).addBox(-64.0F, -48.0F, -32.0F, 16.0F, 48.0F, 16.0F, 0.0F, true); + pillar4.texOffs(0, 21).addBox(-64.5F, -48.5F, -32.5F, 17.0F, 6.0F, 17.0F, 0.0F, true); + pillar4.texOffs(0, 0).addBox(-64.5F, -33.5F, -32.5F, 17.0F, 4.0F, 17.0F, 0.0F, true); + + bone29 = new ModelRenderer(this); + bone29.setPos(4.25F, -27.5F, -14.8F); + pillar4.addChild(bone29); + setRotationAngle(bone29, 0.1745F, 0.1745F, -0.7854F); + bone29.texOffs(0, 0).addBox(-40.9617F, -42.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone29.texOffs(0, 0).addBox(-44.9617F, -38.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone29.texOffs(0, 0).addBox(-48.9617F, -34.2246F, -0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone30 = new ModelRenderer(this); + bone30.setPos(-4.25F, -27.5F, -14.8F); + pillar4.addChild(bone30); + setRotationAngle(bone30, 0.1745F, -0.1745F, 0.7854F); + bone30.texOffs(0, 0).addBox(-41.0311F, 38.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone30.texOffs(0, 0).addBox(-37.0311F, 42.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone30.texOffs(0, 0).addBox(-33.0311F, 46.1562F, -0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone31 = new ModelRenderer(this); + bone31.setPos(4.25F, -27.5F, -33.2F); + pillar4.addChild(bone31); + setRotationAngle(bone31, -0.1745F, -0.1745F, -0.7854F); + bone31.texOffs(0, 0).addBox(-40.9964F, -42.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone31.texOffs(0, 0).addBox(-44.9964F, -38.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone31.texOffs(0, 0).addBox(-48.9964F, -34.1904F, 0.0955F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone32 = new ModelRenderer(this); + bone32.setPos(-4.25F, -27.5F, -33.2F); + pillar4.addChild(bone32); + setRotationAngle(bone32, -0.1745F, 0.1745F, 0.7854F); + bone32.texOffs(0, 0).addBox(-40.9964F, 38.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone32.texOffs(0, 0).addBox(-36.9964F, 42.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone32.texOffs(0, 0).addBox(-32.9964F, 46.1904F, 0.3045F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone33 = new ModelRenderer(this); + bone33.setPos(0.0F, 0.0F, -24.0F); + pillar4.addChild(bone33); + setRotationAngle(bone33, 0.0F, 1.5708F, 0.0F); + + + bone34 = new ModelRenderer(this); + bone34.setPos(4.25F, -27.5F, 9.2F); + bone33.addChild(bone34); + setRotationAngle(bone34, 0.1745F, 0.1745F, -0.7854F); + bone34.texOffs(0, 0).addBox(7.7243F, -11.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone34.texOffs(0, 0).addBox(3.7243F, -7.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone34.texOffs(0, 0).addBox(-0.2757F, -3.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone35 = new ModelRenderer(this); + bone35.setPos(-4.25F, -27.5F, 9.2F); + bone33.addChild(bone35); + setRotationAngle(bone35, 0.1745F, -0.1745F, 0.7854F); + bone35.texOffs(0, 0).addBox(-11.7243F, -11.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone35.texOffs(0, 0).addBox(-7.7243F, -7.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone35.texOffs(0, 0).addBox(-3.7243F, -3.5766F, -54.5114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone36 = new ModelRenderer(this); + bone36.setPos(4.25F, -27.5F, -9.2F); + bone33.addChild(bone36); + setRotationAngle(bone36, -0.1745F, -0.1745F, -0.7854F); + bone36.texOffs(0, 0).addBox(-11.7243F, 7.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone36.texOffs(0, 0).addBox(-15.7243F, 11.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone36.texOffs(0, 0).addBox(-19.7243F, 15.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone37 = new ModelRenderer(this); + bone37.setPos(-4.25F, -27.5F, -9.2F); + bone33.addChild(bone37); + setRotationAngle(bone37, -0.1745F, 0.1745F, 0.7854F); + bone37.texOffs(0, 0).addBox(7.7243F, 7.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone37.texOffs(0, 0).addBox(11.7243F, 11.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone37.texOffs(0, 0).addBox(15.7243F, 15.5766F, -54.1114F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + pillar5 = new ModelRenderer(this); + pillar5.setPos(0.0F, 24.0F, 0.0F); + pillar5.texOffs(0, 44).addBox(-32.0F, -48.0F, 48.0F, 16.0F, 48.0F, 16.0F, 0.0F, true); + pillar5.texOffs(0, 21).addBox(-32.5F, -48.5F, 47.5F, 17.0F, 6.0F, 17.0F, 0.0F, true); + pillar5.texOffs(0, 0).addBox(-32.5F, -33.5F, 47.5F, 17.0F, 4.0F, 17.0F, 0.0F, true); + + bone38 = new ModelRenderer(this); + bone38.setPos(4.25F, -27.5F, 14.8F); + pillar5.addChild(bone38); + setRotationAngle(bone38, -0.1745F, -0.1745F, -0.7854F); + bone38.texOffs(0, 0).addBox(-13.1213F, -24.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone38.texOffs(0, 0).addBox(-17.1213F, -20.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone38.texOffs(0, 0).addBox(-21.1213F, -16.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone39 = new ModelRenderer(this); + bone39.setPos(-4.25F, -27.5F, 14.8F); + pillar5.addChild(bone39); + setRotationAngle(bone39, -0.1745F, 0.1745F, 0.7854F); + bone39.texOffs(0, 0).addBox(-24.3042F, 9.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone39.texOffs(0, 0).addBox(-20.3042F, 13.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone39.texOffs(0, 0).addBox(-16.3042F, 17.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone40 = new ModelRenderer(this); + bone40.setPos(4.25F, -27.5F, 33.2F); + pillar5.addChild(bone40); + setRotationAngle(bone40, 0.1745F, 0.1745F, -0.7854F); + bone40.texOffs(0, 0).addBox(-24.2695F, -13.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone40.texOffs(0, 0).addBox(-28.2695F, -9.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone40.texOffs(0, 0).addBox(-32.2695F, -5.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone41 = new ModelRenderer(this); + bone41.setPos(-4.25F, -27.5F, 33.2F); + pillar5.addChild(bone41); + setRotationAngle(bone41, 0.1745F, -0.1745F, 0.7854F); + bone41.texOffs(0, 0).addBox(-13.156F, 20.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone41.texOffs(0, 0).addBox(-9.156F, 24.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone41.texOffs(0, 0).addBox(-5.156F, 28.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone42 = new ModelRenderer(this); + bone42.setPos(0.0F, 0.0F, 24.0F); + pillar5.addChild(bone42); + setRotationAngle(bone42, 0.0F, -1.5708F, 0.0F); + + + bone43 = new ModelRenderer(this); + bone43.setPos(4.25F, -27.5F, -9.2F); + bone42.addChild(bone43); + setRotationAngle(bone43, -0.1745F, -0.1745F, -0.7854F); + bone43.texOffs(0, 0).addBox(24.4512F, 16.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone43.texOffs(0, 0).addBox(20.4512F, 20.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone43.texOffs(0, 0).addBox(16.4512F, 24.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone44 = new ModelRenderer(this); + bone44.setPos(-4.25F, -27.5F, -9.2F); + bone42.addChild(bone44); + setRotationAngle(bone44, -0.1745F, 0.1745F, 0.7854F); + bone44.texOffs(0, 0).addBox(16.1161F, -29.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone44.texOffs(0, 0).addBox(20.1161F, -25.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone44.texOffs(0, 0).addBox(24.1161F, -21.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone45 = new ModelRenderer(this); + bone45.setPos(4.25F, -27.5F, 9.2F); + bone42.addChild(bone45); + setRotationAngle(bone45, 0.1745F, 0.1745F, -0.7854F); + bone45.texOffs(0, 0).addBox(16.1161F, 25.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone45.texOffs(0, 0).addBox(12.1161F, 29.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone45.texOffs(0, 0).addBox(8.1161F, 33.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone46 = new ModelRenderer(this); + bone46.setPos(-4.25F, -27.5F, 9.2F); + bone42.addChild(bone46); + setRotationAngle(bone46, 0.1745F, -0.1745F, 0.7854F); + bone46.texOffs(0, 0).addBox(24.4512F, -20.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone46.texOffs(0, 0).addBox(28.4512F, -16.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone46.texOffs(0, 0).addBox(32.4512F, -12.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + pillar6 = new ModelRenderer(this); + pillar6.setPos(0.0F, 24.0F, 0.0F); + pillar6.texOffs(0, 44).addBox(16.0F, -48.0F, 48.0F, 16.0F, 48.0F, 16.0F, 0.0F, false); + pillar6.texOffs(0, 21).addBox(15.5F, -48.5F, 47.5F, 17.0F, 6.0F, 17.0F, 0.0F, false); + pillar6.texOffs(0, 0).addBox(15.5F, -33.5F, 47.5F, 17.0F, 4.0F, 17.0F, 0.0F, false); + + bone47 = new ModelRenderer(this); + bone47.setPos(-4.25F, -27.5F, 14.8F); + pillar6.addChild(bone47); + setRotationAngle(bone47, -0.1745F, 0.1745F, 0.7854F); + bone47.texOffs(0, 0).addBox(9.1213F, -24.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone47.texOffs(0, 0).addBox(13.1213F, -20.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone47.texOffs(0, 0).addBox(17.1213F, -16.731F, 31.1903F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone48 = new ModelRenderer(this); + bone48.setPos(4.25F, -27.5F, 14.8F); + pillar6.addChild(bone48); + setRotationAngle(bone48, -0.1745F, -0.1745F, -0.7854F); + bone48.texOffs(0, 0).addBox(20.3042F, 9.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone48.texOffs(0, 0).addBox(16.3042F, 13.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone48.texOffs(0, 0).addBox(12.3042F, 17.7179F, 31.2799F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone49 = new ModelRenderer(this); + bone49.setPos(-4.25F, -27.5F, 33.2F); + pillar6.addChild(bone49); + setRotationAngle(bone49, 0.1745F, -0.1745F, 0.7854F); + bone49.texOffs(0, 0).addBox(20.2695F, -13.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone49.texOffs(0, 0).addBox(24.2695F, -9.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone49.texOffs(0, 0).addBox(28.2695F, -5.7521F, 30.8799F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone50 = new ModelRenderer(this); + bone50.setPos(4.25F, -27.5F, 33.2F); + pillar6.addChild(bone50); + setRotationAngle(bone50, 0.1745F, 0.1745F, -0.7854F); + bone50.texOffs(0, 0).addBox(9.156F, 20.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone50.texOffs(0, 0).addBox(5.156F, 24.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone50.texOffs(0, 0).addBox(1.156F, 28.6968F, 30.7903F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone51 = new ModelRenderer(this); + bone51.setPos(0.0F, 0.0F, 24.0F); + pillar6.addChild(bone51); + setRotationAngle(bone51, 0.0F, 1.5708F, 0.0F); + + + bone52 = new ModelRenderer(this); + bone52.setPos(-4.25F, -27.5F, -9.2F); + bone51.addChild(bone52); + setRotationAngle(bone52, -0.1745F, 0.1745F, 0.7854F); + bone52.texOffs(0, 0).addBox(-28.4512F, 16.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone52.texOffs(0, 0).addBox(-24.4512F, 20.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone52.texOffs(0, 0).addBox(-20.4512F, 24.8617F, 23.536F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone53 = new ModelRenderer(this); + bone53.setPos(4.25F, -27.5F, -9.2F); + bone51.addChild(bone53); + setRotationAngle(bone53, -0.1745F, -0.1745F, -0.7854F); + bone53.texOffs(0, 0).addBox(-20.1161F, -29.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone53.texOffs(0, 0).addBox(-24.1161F, -25.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone53.texOffs(0, 0).addBox(-28.1161F, -21.0702F, 23.4166F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone54 = new ModelRenderer(this); + bone54.setPos(-4.25F, -27.5F, 9.2F); + bone51.addChild(bone54); + setRotationAngle(bone54, 0.1745F, -0.1745F, 0.7854F); + bone54.texOffs(0, 0).addBox(-20.1161F, 25.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone54.texOffs(0, 0).addBox(-16.1161F, 29.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + bone54.texOffs(0, 0).addBox(-12.1161F, 33.0702F, 23.0166F, 4.0F, 4.0F, 0.0F, 0.0F, false); + + bone55 = new ModelRenderer(this); + bone55.setPos(4.25F, -27.5F, 9.2F); + bone51.addChild(bone55); + setRotationAngle(bone55, 0.1745F, 0.1745F, -0.7854F); + bone55.texOffs(0, 0).addBox(-28.4512F, -20.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone55.texOffs(0, 0).addBox(-32.4512F, -16.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, true); + bone55.texOffs(0, 0).addBox(-36.4512F, -12.8617F, 23.136F, 4.0F, 4.0F, 0.0F, 0.0F, true); + + bone = new ModelRenderer(this); + bone.setPos(0.0F, 24.0F, 0.0F); + bone.texOffs(64, 39).addBox(-24.0F, -1.0F, -24.0F, 48.0F, 0.0F, 48.0F, 0.0F, false); + + bone56 = new ModelRenderer(this); + bone56.setPos(0.0F, 24.0F, 0.0F); + bone56.texOffs(150, 227).addBox(-32.0F, -12.0F, -64.0F, 16.0F, 12.0F, 16.0F, 0.0F, false); + bone56.texOffs(150, 227).addBox(16.0F, -12.0F, -64.0F, 16.0F, 12.0F, 16.0F, 0.0F, true); + bone56.texOffs(0, 236).addBox(-60.0F, -101.0F, -58.0F, 120.0F, 6.0F, 4.0F, 0.0F, false); + bone56.texOffs(2, 176).addBox(-54.5F, -95.0F, -64.0F, 109.0F, 3.0F, 16.0F, 0.0F, false); + bone56.texOffs(0, 186).addBox(-45.0F, -66.3F, -57.0F, 90.0F, 8.0F, 2.0F, 0.0F, false); + bone56.texOffs(192, 171).addBox(-32.0F, -42.0F, -64.0F, 16.0F, 30.0F, 16.0F, 0.0F, false); + bone56.texOffs(192, 171).addBox(16.0F, -42.0F, -64.0F, 16.0F, 30.0F, 16.0F, 0.0F, true); + bone56.texOffs(153, 188).addBox(16.5F, -55.0F, -63.5F, 15.0F, 13.0F, 15.0F, 0.0F, true); + bone56.texOffs(153, 188).addBox(-31.5F, -55.0F, -63.5F, 15.0F, 13.0F, 15.0F, 0.0F, false); + bone56.texOffs(49, 184).addBox(17.0F, -73.0F, -63.0F, 14.0F, 18.0F, 14.0F, 0.0F, true); + bone56.texOffs(49, 184).addBox(-31.0F, -73.0F, -63.0F, 14.0F, 18.0F, 14.0F, 0.0F, false); + bone56.texOffs(30, 173).addBox(17.5F, -85.0F, -62.5F, 13.0F, 12.0F, 13.0F, 0.0F, true); + bone56.texOffs(30, 173).addBox(-30.5F, -85.0F, -62.5F, 13.0F, 12.0F, 13.0F, 0.0F, false); + bone56.texOffs(0, 192).addBox(17.0F, -92.0F, -63.0F, 14.0F, 7.0F, 14.0F, 0.0F, true); + bone56.texOffs(0, 192).addBox(-31.0F, -92.0F, -63.0F, 14.0F, 7.0F, 14.0F, 0.0F, false); + bone56.texOffs(28, 208).addBox(-47.0F, -68.3F, -59.0F, 94.0F, 2.0F, 6.0F, 0.0F, false); + bone56.texOffs(0, 180).addBox(-50.5F, -92.0F, -60.0F, 101.0F, 5.0F, 8.0F, 0.0F, false); + + bone57 = new ModelRenderer(this); + bone57.setPos(0.0F, -98.0F, -56.5F); + bone56.addChild(bone57); + setRotationAngle(bone57, 0.2618F, 0.0F, 0.0F); + bone57.texOffs(0, 228).addBox(-55.5F, -1.0F, -14.5F, 111.0F, 2.0F, 14.0F, 0.0F, false); + + bone58 = new ModelRenderer(this); + bone58.setPos(0.0F, -98.0F, -55.5F); + bone56.addChild(bone58); + setRotationAngle(bone58, -0.2618F, 0.0F, 0.0F); + bone58.texOffs(0, 222).addBox(-55.5F, -1.0F, 0.5F, 111.0F, 2.0F, 14.0F, 0.0F, false); + + bone59 = new ModelRenderer(this); + bone59.setPos(0.0F, -67.3F, -59.25F); + bone56.addChild(bone59); + setRotationAngle(bone59, 0.0873F, 0.0F, 0.0F); + bone59.texOffs(224, 234).addBox(-6.0F, -20.0F, -1.0F, 12.0F, 20.0F, 2.0F, 0.0F, false); + bone59.texOffs(230, 7).addBox(-4.5F, -18.5F, -1.7F, 9.0F, 17.0F, 2.0F, 0.0F, false); + + bone60 = new ModelRenderer(this); + bone60.setPos(0.0F, -67.3F, -52.75F); + bone56.addChild(bone60); + setRotationAngle(bone60, -0.0873F, 0.0F, 0.0F); + bone60.texOffs(224, 234).addBox(-6.0F, -20.0F, -1.0F, 12.0F, 20.0F, 2.0F, 0.0F, false); + bone60.texOffs(230, 7).addBox(-4.5F, -18.5F, -0.25F, 9.0F, 17.0F, 2.0F, 0.0F, false); + + bone61 = new ModelRenderer(this); + bone61.setPos(0.0F, 0.0F, 0.0F); + bone56.addChild(bone61); + bone61.texOffs(16, 243).addBox(35.25F, -8.0F, -58.0F, 4.0F, 8.0F, 4.0F, 0.0F, true); + bone61.texOffs(5, 178).addBox(35.25F, -27.0F, -58.0F, 4.0F, 19.0F, 4.0F, 0.0F, true); + bone61.texOffs(5, 180).addBox(32.0F, -24.0F, -57.0F, 9.0F, 2.0F, 2.0F, 0.0F, true); + bone61.texOffs(217, 178).addBox(32.0F, -31.0F, -58.5F, 12.0F, 4.0F, 5.0F, 0.0F, true); + + bone63 = new ModelRenderer(this); + bone63.setPos(38.0F, -31.75F, -56.0F); + bone61.addChild(bone63); + setRotationAngle(bone63, 0.0F, 0.0F, 0.0873F); + bone63.texOffs(204, 236).addBox(-6.0F, -0.5F, -3.0F, 14.0F, 2.0F, 6.0F, 0.0F, true); + + bone62 = new ModelRenderer(this); + bone62.setPos(0.0F, 0.0F, 0.0F); + bone56.addChild(bone62); + bone62.texOffs(16, 243).addBox(-39.25F, -8.0F, -58.0F, 4.0F, 8.0F, 4.0F, 0.0F, false); + bone62.texOffs(5, 178).addBox(-39.25F, -27.0F, -58.0F, 4.0F, 19.0F, 4.0F, 0.0F, false); + bone62.texOffs(5, 180).addBox(-41.0F, -24.0F, -57.0F, 9.0F, 2.0F, 2.0F, 0.0F, false); + bone62.texOffs(217, 178).addBox(-44.0F, -31.0F, -58.5F, 12.0F, 4.0F, 5.0F, 0.0F, false); + + bone64 = new ModelRenderer(this); + bone64.setPos(-38.0F, -31.75F, -56.0F); + bone62.addChild(bone64); + setRotationAngle(bone64, 0.0F, 0.0F, -0.0873F); + bone64.texOffs(204, 236).addBox(-8.0F, -0.5F, -3.0F, 14.0F, 2.0F, 6.0F, 0.0F, false); + } + + @Override + public void setupAnim(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + } + + @Override + public void renderToBuffer(MatrixStack matrixStack, IVertexBuilder buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + pillar.render(matrixStack, buffer, packedLight, packedOverlay); + pillar2.render(matrixStack, buffer, packedLight, packedOverlay); + pillar3.render(matrixStack, buffer, packedLight, packedOverlay); + pillar4.render(matrixStack, buffer, packedLight, packedOverlay); + pillar5.render(matrixStack, buffer, packedLight, packedOverlay); + pillar6.render(matrixStack, buffer, packedLight, packedOverlay); + bone.render(matrixStack, buffer, packedLight, packedOverlay); + bone56.render(matrixStack, buffer, packedLight, packedOverlay); + } + + public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) { + modelRenderer.xRot = x; + modelRenderer.yRot = y; + modelRenderer.zRot = z; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityAltarRenderer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityAltarRenderer.java new file mode 100644 index 000000000..c036aca11 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityAltarRenderer.java @@ -0,0 +1,71 @@ +package com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.client.model.AltarModel; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Vector3f; + +import static net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType.GROUND; + +public class TileEntityAltarRenderer extends TileEntityRenderer { + private static final AltarModel MODEL = new AltarModel(); + private static final ResourceLocation TEXTURE = new ResourceLocation(TouhouLittleMaid.MOD_ID, "textures/entity/altar.png"); + + public TileEntityAltarRenderer(TileEntityRendererDispatcher render) { + super(render); + } + + @Override + public void render(TileEntityAltar te, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn) { + if (te.isRender()) { + matrixStack.pushPose(); + this.setTranslateAndPose(te, matrixStack); + matrixStack.mulPose(Vector3f.ZN.rotationDegrees(180)); + IVertexBuilder buffer = bufferIn.getBuffer(RenderType.entityTranslucent(TEXTURE)); + MODEL.renderToBuffer(matrixStack, buffer, combinedLightIn, combinedOverlayIn, 1.0F, 1.0F, 1.0F, 1.0F); + matrixStack.popPose(); + } + + if (te.isCanPlaceItem() && !te.handler.getStackInSlot(0).isEmpty()) { + ItemStack stack = te.handler.getStackInSlot(0); + matrixStack.pushPose(); + matrixStack.translate(0.5, 1.25, 0.5); + Minecraft.getInstance().getItemRenderer().renderStatic(stack, GROUND, combinedLightIn, combinedOverlayIn, matrixStack, bufferIn); + matrixStack.popPose(); + } + } + + @Override + public boolean shouldRenderOffScreen(TileEntityAltar te) { + return true; + } + + private void setTranslateAndPose(TileEntityAltar te, MatrixStack matrixStackIn) { + switch (te.getDirection()) { + case SOUTH: + matrixStackIn.translate(1, -1.5, -3); + matrixStackIn.mulPose(Vector3f.YP.rotationDegrees(180)); + break; + case EAST: + matrixStackIn.translate(-3, -1.5, 0); + matrixStackIn.mulPose(Vector3f.YP.rotationDegrees(270)); + break; + case WEST: + matrixStackIn.translate(4, -1.5, 1); + matrixStackIn.mulPose(Vector3f.YP.rotationDegrees(90)); + break; + case NORTH: + default: + matrixStackIn.translate(0, -1.5, 4); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/package-info.java new file mode 100644 index 000000000..d34975087 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipe.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipe.java new file mode 100644 index 000000000..fc97820f5 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipe.java @@ -0,0 +1,110 @@ +package com.github.tartaricacid.touhoulittlemaid.crafting; + +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitRecipes; +import com.github.tartaricacid.touhoulittlemaid.inventory.AltarRecipeInventory; +import com.google.common.base.Preconditions; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnReason; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.RecipeMatcher; + +import javax.annotation.Nullable; + +import static com.github.tartaricacid.touhoulittlemaid.inventory.AltarRecipeInventory.RECIPES_SIZE; + +public class AltarRecipe implements IRecipe { + private final ResourceLocation id; + private final EntityType entityType; + @Nullable + private final CompoundNBT extraData; + private final float powerCost; + private final NonNullList inputs; + + public AltarRecipe(ResourceLocation id, EntityType entityType, @Nullable CompoundNBT extraData, float powerCost, Ingredient... inputs) { + Preconditions.checkArgument(0 < inputs.length && inputs.length <= RECIPES_SIZE, "Ingredients count is illegal!"); + this.id = id; + this.entityType = entityType; + this.extraData = extraData; + this.powerCost = powerCost; + this.inputs = NonNullList.of(Ingredient.EMPTY, inputs); + } + + @Override + public boolean matches(AltarRecipeInventory inv, World worldIn) { + return RecipeMatcher.findMatches(inv.getItems(), inputs) != null; + } + + @Override + public ItemStack assemble(AltarRecipeInventory inv) { + return getResultItem().copy(); + } + + @Override + public boolean canCraftInDimensions(int width, int height) { + return false; + } + + @Override + public NonNullList getIngredients() { + return inputs; + } + + @Override + public ItemStack getResultItem() { + return ItemStack.EMPTY; + } + + @Override + public ResourceLocation getId() { + return this.id; + } + + @Override + public IRecipeSerializer getSerializer() { + return new AltarRecipeSerializer(); + } + + @Override + public IRecipeType getType() { + return InitRecipes.ALTAR_CRAFTING; + } + + @Override + public boolean isSpecial() { + return true; + } + + @Override + public ItemStack getToastSymbol() { + return InitItems.HAKUREI_GOHEI.get().getDefaultInstance(); + } + + public EntityType getEntityType() { + return entityType; + } + + @Nullable + public CompoundNBT getExtraData() { + return extraData; + } + + public float getPowerCost() { + return powerCost; + } + + public void spawnOutputEntity(ServerWorld world, BlockPos pos, AltarRecipeInventory inventory) { + entityType.spawn(world, extraData, StringTextComponent.EMPTY, null, pos, SpawnReason.SPAWN_EGG, true, true); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipeSerializer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipeSerializer.java new file mode 100644 index 000000000..8ac76be48 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/AltarRecipeSerializer.java @@ -0,0 +1,67 @@ +package com.github.tartaricacid.touhoulittlemaid.crafting; + +import com.github.tartaricacid.touhoulittlemaid.util.EntityCraftingHelper; +import com.google.common.collect.Lists; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.util.Pair; +import net.minecraft.entity.EntityType; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.ForgeRegistryEntry; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; + +public class AltarRecipeSerializer extends ForgeRegistryEntry> implements IRecipeSerializer { + @Override + public AltarRecipe fromJson(ResourceLocation recipeId, JsonObject json) { + Pair, CompoundNBT> output = EntityCraftingHelper.getEntityData(JSONUtils.getAsJsonObject(json, "output")); + float powerCost = JSONUtils.getAsFloat(json, "power"); + JsonArray ingredients = JSONUtils.getAsJsonArray(json, "ingredients"); + List inputs = Lists.newArrayList(); + for (JsonElement e : ingredients) { + inputs.add(Ingredient.fromJson(e)); + } + return new AltarRecipe(recipeId, output.getFirst(), output.getSecond(), powerCost, inputs.toArray(new Ingredient[0])); + } + + @Nullable + @Override + public AltarRecipe fromNetwork(ResourceLocation recipeId, PacketBuffer buffer) { + Optional> typeOptional = EntityType.byString(buffer.readUtf()); + if (typeOptional.isPresent()) { + EntityType entityType = typeOptional.get(); + CompoundNBT extraData = buffer.readNbt(); + float powerCost = buffer.readFloat(); + Ingredient[] inputs = new Ingredient[buffer.readVarInt()]; + for (int i = 0; i < inputs.length; i++) { + inputs[i] = Ingredient.fromNetwork(buffer); + } + return new AltarRecipe(recipeId, entityType, extraData, powerCost, inputs); + } + throw new JsonParseException("Entity Type Tag Not Found"); + } + + @Override + public void toNetwork(PacketBuffer buffer, AltarRecipe recipe) { + ResourceLocation name = recipe.getEntityType().getRegistryName(); + if (name != null) { + buffer.writeUtf(name.toString()); + buffer.writeNbt(recipe.getExtraData()); + buffer.writeFloat(recipe.getPowerCost()); + buffer.writeVarInt(recipe.getIngredients().size()); + for (Ingredient input : recipe.getIngredients()) { + input.toNetwork(buffer); + } + } + throw new JsonParseException("Entity Type Tag Not Found"); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/package-info.java new file mode 100644 index 000000000..d69862974 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/crafting/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.crafting; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/AltarRecipeProvider.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/AltarRecipeProvider.java new file mode 100644 index 000000000..59fc4dd73 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/AltarRecipeProvider.java @@ -0,0 +1,92 @@ +package com.github.tartaricacid.touhoulittlemaid.data; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.crafting.AltarRecipe; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitRecipes; +import com.google.common.collect.Lists; +import com.google.gson.*; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DirectoryCache; +import net.minecraft.data.IDataProvider; +import net.minecraft.entity.EntityType; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.Tags; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +public class AltarRecipeProvider implements IDataProvider { + private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create(); + protected final DataGenerator generator; + private final List recipes = Lists.newArrayList(); + + public AltarRecipeProvider(DataGenerator generator) { + this.generator = generator; + } + + @Override + public void run(DirectoryCache cache) throws IOException { + Path path = this.generator.getOutputFolder(); + recipes.clear(); + this.registerRecipes(); + for (AltarRecipe recipe : recipes) { + JsonObject jsonObject = recipeToJson(recipe); + Path savePath = path.resolve("data/" + recipe.getId().getNamespace() + "/recipes/altar/" + recipe.getId().getPath() + ".json"); + IDataProvider.save(GSON, cache, jsonObject, savePath); + } + } + + protected void registerRecipes() { + addItemRecipes(new ResourceLocation(TouhouLittleMaid.MOD_ID, "craft_explosion_protect_bauble"), + InitItems.EXPLOSION_PROTECT_BAUBLE.get().getDefaultInstance(), 0.2f, + Ingredient.of(Items.NETHER_WART), Ingredient.of(Tags.Items.DYES_ORANGE), Ingredient.of(Tags.Items.OBSIDIAN), + Ingredient.of(Tags.Items.OBSIDIAN), Ingredient.of(Tags.Items.OBSIDIAN), Ingredient.of(Tags.Items.OBSIDIAN)); + } + + public void addRecipes(AltarRecipe recipe) { + recipes.add(recipe); + } + + public void addItemRecipes(ResourceLocation id, ItemStack output, float powerCost, Ingredient... inputs) { + CompoundNBT extraData = new CompoundNBT(); + extraData.put("Item", output.serializeNBT()); + addRecipes(new AltarRecipe(id, EntityType.ITEM, extraData, powerCost, inputs)); + } + + private JsonObject recipeToJson(AltarRecipe recipe) { + JsonObject json = new JsonObject(); + json.addProperty("type", InitRecipes.ALTAR_CRAFTING.toString()); + { + JsonObject output = new JsonObject(); + ResourceLocation name = recipe.getEntityType().getRegistryName(); + if (name == null) { + throw new JsonParseException("Entity Registry Name Not Found"); + } + output.addProperty("type", name.toString()); + if (recipe.getExtraData() != null) { + output.addProperty("nbt", recipe.getExtraData().getAsString()); + } + json.add("output", output); + } + json.addProperty("power", recipe.getPowerCost()); + { + JsonArray ingredients = new JsonArray(); + for (Ingredient ingredient : recipe.getIngredients()) { + ingredients.add(ingredient.toJson()); + } + json.add("ingredients", ingredients); + } + return json; + } + + @Override + public String getName() { + return "Maid Altar Recipe"; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/DataGenEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/DataGenEvent.java index 4f489757e..a42bc5fbc 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/DataGenEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/DataGenEvent.java @@ -10,5 +10,6 @@ public class DataGenEvent { @SubscribeEvent public static void dataGen(GatherDataEvent event) { event.getGenerator().addProvider(new MaidBlockStateProvider(event.getGenerator(), TouhouLittleMaid.MOD_ID, event.getExistingFileHelper())); + event.getGenerator().addProvider(new AltarRecipeProvider(event.getGenerator())); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/package-info.java new file mode 100644 index 000000000..004a06378 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/data/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.data; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskManager.java index 69b6868d1..c84bedd2c 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskManager.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskManager.java @@ -26,24 +26,24 @@ private TaskManager() { public static void init() { TaskManager manager = new TaskManager(); - manager.registerTask(IDLE_TASK); - manager.registerTask(new TaskAttack()); - manager.registerTask(new TaskBowAttack()); - manager.registerTask(new TaskDanmakuAttack()); - manager.registerTask(new TaskNormalFarm()); - manager.registerTask(new TaskSugarCane()); - manager.registerTask(new TaskMelon()); - manager.registerTask(new TaskCocoa()); - manager.registerTask(new TaskGrass()); - manager.registerTask(new TaskSnow()); - manager.registerTask(new TaskFeedOwner()); - manager.registerTask(new TaskShears()); - manager.registerTask(new TaskMilk()); - manager.registerTask(new TaskTorch()); - manager.registerTask(new TaskFeedAnimal()); - manager.registerTask(new TaskExtinguishing()); + manager.add(IDLE_TASK); + manager.add(new TaskAttack()); + manager.add(new TaskBowAttack()); + manager.add(new TaskDanmakuAttack()); + manager.add(new TaskNormalFarm()); + manager.add(new TaskSugarCane()); + manager.add(new TaskMelon()); + manager.add(new TaskCocoa()); + manager.add(new TaskGrass()); + manager.add(new TaskSnow()); + manager.add(new TaskFeedOwner()); + manager.add(new TaskShears()); + manager.add(new TaskMilk()); + manager.add(new TaskTorch()); + manager.add(new TaskFeedAnimal()); + manager.add(new TaskExtinguishing()); for (ILittleMaid littleMaid : TouhouLittleMaid.EXTENSIONS) { - littleMaid.registerMaidTask(manager); + littleMaid.addMaidTask(manager); } TASK_MAP = ImmutableMap.copyOf(TASK_MAP); TASK_INDEX = ImmutableList.copyOf(TASK_INDEX); @@ -74,7 +74,7 @@ public static List getTaskIndex() { /** * 注册 Task */ - public void registerTask(IMaidTask task) { + public void add(IMaidTask task) { TASK_MAP.put(task.getUid(), task); TASK_INDEX.add(task); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java index c59099815..73edd533b 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java @@ -1,14 +1,21 @@ package com.github.tartaricacid.touhoulittlemaid.init; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.block.BlockAltar; import com.github.tartaricacid.touhoulittlemaid.block.BlockMaidBed; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntityType; import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; public final class InitBlocks { public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, TouhouLittleMaid.MOD_ID); + public static final DeferredRegister> TILE_ENTITIES = DeferredRegister.create(ForgeRegistries.TILE_ENTITIES, TouhouLittleMaid.MOD_ID); public static RegistryObject MAID_BED = BLOCKS.register("maid_bed", BlockMaidBed::new); + public static RegistryObject ALTAR = BLOCKS.register("altar", BlockAltar::new); + + public static RegistryObject> ALTAR_TE = TILE_ENTITIES.register("altar", () -> TileEntityAltar.TYPE); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java index 6aec84f32..c43dbee04 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java @@ -8,11 +8,9 @@ import net.minecraft.item.ItemGroup; import net.minecraft.item.SpawnEggItem; import net.minecraftforge.fml.RegistryObject; -import net.minecraftforge.fml.common.Mod; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public final class InitItems { public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, TouhouLittleMaid.MOD_ID); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitRecipes.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitRecipes.java new file mode 100644 index 000000000..bc91c26d4 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitRecipes.java @@ -0,0 +1,38 @@ +package com.github.tartaricacid.touhoulittlemaid.init; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.crafting.AltarRecipe; +import com.github.tartaricacid.touhoulittlemaid.crafting.AltarRecipeSerializer; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public final class InitRecipes { + public static final DeferredRegister> RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, TouhouLittleMaid.MOD_ID); + + public static RegistryObject> ALTAR_RECIPE_SERIALIZER = RECIPE_SERIALIZERS.register("altar_crafting", AltarRecipeSerializer::new); + public static IRecipeType ALTAR_CRAFTING; + + @SubscribeEvent + public static void register(RegistryEvent.Register> evt) { + ALTAR_CRAFTING = register(TouhouLittleMaid.MOD_ID + ":altar_crafting"); + } + + private static > IRecipeType register(final String key) { + return Registry.register(Registry.RECIPE_TYPE, new ResourceLocation(key), new IRecipeType() { + @Override + public String toString() { + return key; + } + }); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarItemHandler.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarItemHandler.java new file mode 100644 index 000000000..6dcae7a24 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarItemHandler.java @@ -0,0 +1,10 @@ +package com.github.tartaricacid.touhoulittlemaid.inventory; + +import net.minecraftforge.items.ItemStackHandler; + +public class AltarItemHandler extends ItemStackHandler { + @Override + public int getSlotLimit(int slot) { + return 1; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarRecipeInventory.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarRecipeInventory.java new file mode 100644 index 000000000..aa0a07012 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/AltarRecipeInventory.java @@ -0,0 +1,68 @@ +package com.github.tartaricacid.touhoulittlemaid.inventory; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ItemStackHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; + +public class AltarRecipeInventory implements IInventory { + public static final int RECIPES_SIZE = 6; + public final NonNullList items = NonNullList.withSize(RECIPES_SIZE, ItemStack.EMPTY); + + public AltarRecipeInventory() { + } + + @Override + public int getContainerSize() { + return RECIPES_SIZE; + } + + @Override + public boolean isEmpty() { + for (ItemStack stack : this.items) { + if (!stack.isEmpty()) { + return false; + } + } + return true; + } + + @Override + public ItemStack getItem(int index) { + return this.getContainerSize() <= index ? ItemStack.EMPTY : this.items.get(index); + } + + @Override + public ItemStack removeItem(int index, int count) { + return ItemStackHelper.removeItem(this.items, index, count); + } + + @Override + public ItemStack removeItemNoUpdate(int index) { + return ItemStackHelper.takeItem(this.items, index); + } + + @Override + public void setItem(int index, ItemStack stack) { + this.items.set(index, stack); + } + + @Override + public void setChanged() { + } + + @Override + public boolean stillValid(PlayerEntity player) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + } + + public NonNullList getItems() { + return items; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java index 994fba29d..4665c4599 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java @@ -1,11 +1,23 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.api.block.IMultiBlock; +import com.github.tartaricacid.touhoulittlemaid.block.multiblock.MultiBlockManager; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; import com.google.common.base.Predicates; +import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; import net.minecraft.item.ShootableItem; import net.minecraft.item.UseAction; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraft.world.server.ServerWorld; +import java.util.List; import java.util.function.Predicate; public class ItemHakureiGohei extends ShootableItem { @@ -32,4 +44,29 @@ public int getUseDuration(ItemStack stack) { public UseAction getUseAnimation(ItemStack stack) { return UseAction.BOW; } + + @Override + public ActionResultType useOn(ItemUseContext context) { + if (context.getHand() == Hand.MAIN_HAND) { + List multiBlockList = MultiBlockManager.getMultiBlockList(); + BlockState blockState = context.getLevel().getBlockState(context.getClickedPos()); + World world = context.getLevel(); + BlockPos pos = context.getClickedPos(); + Direction direction = context.getClickedFace(); + + for (IMultiBlock multiBlock : multiBlockList) { + if (multiBlock.isCoreBlock(blockState) && multiBlock.directionIsSuitable(direction)) { + if (world instanceof ServerWorld) { + BlockPos posStart = pos.offset(multiBlock.getCenterPos(direction)); + Template template = multiBlock.getTemplate((ServerWorld) world, direction); + if (multiBlock.isMatch(world, posStart, direction, template)) { + multiBlock.build(world, posStart, direction, template); + } + } + return ActionResultType.SUCCESS; + } + } + } + return super.useOn(context); + } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/BaubleManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/BaubleManager.java index 5401d2104..ac5aa6f03 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/BaubleManager.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/BaubleManager.java @@ -23,17 +23,17 @@ private BaubleManager() { public static void init() { BaubleManager manager = new BaubleManager(); - manager.bindBauble(InitItems.DROWN_PROTECT_BAUBLE, new DrownProtectBauble()); - manager.bindBauble(InitItems.EXPLOSION_PROTECT_BAUBLE, new ExplosionProtectBauble()); - manager.bindBauble(InitItems.ULTRAMARINE_ORB_ELIXIR, new ExtraLifeBauble()); - manager.bindBauble(InitItems.FALL_PROTECT_BAUBLE, new FallProtectBauble()); - manager.bindBauble(InitItems.FIRE_PROTECT_BAUBLE, new FireProtectBauble()); - manager.bindBauble(InitItems.ITEM_MAGNET_BAUBLE, new ItemMagnetBauble()); - manager.bindBauble(InitItems.MAGIC_PROTECT_BAUBLE, new MagicProtectBauble()); - manager.bindBauble(InitItems.NIMBLE_FABRIC, new NimbleFabricBauble()); - manager.bindBauble(InitItems.PROJECTILE_PROTECT_BAUBLE, new ProjectileProtectBauble()); - manager.bindBauble(InitItems.MUTE_BAUBLE, new MuteBauble()); - manager.bindBauble(Items.TOTEM_OF_UNDYING, new UndyingTotemBauble()); + manager.bind(InitItems.DROWN_PROTECT_BAUBLE, new DrownProtectBauble()); + manager.bind(InitItems.EXPLOSION_PROTECT_BAUBLE, new ExplosionProtectBauble()); + manager.bind(InitItems.ULTRAMARINE_ORB_ELIXIR, new ExtraLifeBauble()); + manager.bind(InitItems.FALL_PROTECT_BAUBLE, new FallProtectBauble()); + manager.bind(InitItems.FIRE_PROTECT_BAUBLE, new FireProtectBauble()); + manager.bind(InitItems.ITEM_MAGNET_BAUBLE, new ItemMagnetBauble()); + manager.bind(InitItems.MAGIC_PROTECT_BAUBLE, new MagicProtectBauble()); + manager.bind(InitItems.NIMBLE_FABRIC, new NimbleFabricBauble()); + manager.bind(InitItems.PROJECTILE_PROTECT_BAUBLE, new ProjectileProtectBauble()); + manager.bind(InitItems.MUTE_BAUBLE, new MuteBauble()); + manager.bind(Items.TOTEM_OF_UNDYING, new UndyingTotemBauble()); for (ILittleMaid littleMaid : TouhouLittleMaid.EXTENSIONS) { littleMaid.bindMaidBauble(manager); } @@ -51,11 +51,11 @@ public static IMaidBauble getBauble(ItemStack stack) { return getBauble(RegistryObject.of(item.getRegistryName(), item::getRegistryType)); } - public void bindBauble(RegistryObject item, IMaidBauble bauble) { + public void bind(RegistryObject item, IMaidBauble bauble) { BAUBLES.put(item, bauble); } - public void bindBauble(Item item, IMaidBauble bauble) { + public void bind(Item item, IMaidBauble bauble) { BAUBLES.put(RegistryObject.of(item.getRegistryName(), item::getRegistryType), bauble); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityAltar.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityAltar.java new file mode 100644 index 000000000..0632d2d9d --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityAltar.java @@ -0,0 +1,145 @@ +package com.github.tartaricacid.touhoulittlemaid.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; +import com.github.tartaricacid.touhoulittlemaid.inventory.AltarItemHandler; +import com.github.tartaricacid.touhoulittlemaid.util.PosListData; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.items.ItemStackHandler; + +import javax.annotation.Nullable; + +public class TileEntityAltar extends TileEntity { + public static final TileEntityType TYPE = TileEntityType.Builder.of(TileEntityAltar::new, InitBlocks.ALTAR.get()).build(null); + + private static final String STORAGE_ITEM = "StorageItem"; + private static final String IS_RENDER = "IsRender"; + private static final String CAN_PLACE_ITEM = "CanPlaceItem"; + private static final String STORAGE_STATE_ID = "StorageBlockStateId"; + private static final String DIRECTION = "Direction"; + private static final String STORAGE_BLOCK_LIST = "StorageBlockList"; + private static final String CAN_PLACE_ITEM_POS_LIST = "CanPlaceItemPosList"; + + public final ItemStackHandler handler = new AltarItemHandler(); + + private boolean isRender = false; + private boolean canPlaceItem = false; + private BlockState storageState = Blocks.AIR.defaultBlockState(); + private PosListData blockPosList = new PosListData(); + private PosListData canPlaceItemPosList = new PosListData(); + private Direction direction = Direction.SOUTH; + + public TileEntityAltar() { + super(TYPE); + } + + public void setForgeData(BlockState storageState, boolean isRender, boolean canPlaceItem, Direction direction, + PosListData blockPosList, PosListData canPlaceItemPosList) { + this.isRender = isRender; + this.canPlaceItem = canPlaceItem; + this.storageState = storageState; + this.direction = direction; + this.blockPosList = blockPosList; + this.canPlaceItemPosList = canPlaceItemPosList; + refresh(); + } + + @Override + public CompoundNBT save(CompoundNBT compound) { + getTileData().putBoolean(IS_RENDER, isRender); + getTileData().putBoolean(CAN_PLACE_ITEM, canPlaceItem); + getTileData().putInt(STORAGE_STATE_ID, Block.getId(storageState)); + getTileData().put(STORAGE_ITEM, handler.serializeNBT()); + getTileData().putString(DIRECTION, direction.getSerializedName()); + getTileData().put(STORAGE_BLOCK_LIST, blockPosList.serialize()); + getTileData().put(CAN_PLACE_ITEM_POS_LIST, canPlaceItemPosList.serialize()); + return super.save(compound); + } + + @Override + public void load(BlockState state, CompoundNBT nbt) { + super.load(state, nbt); + isRender = getTileData().getBoolean(IS_RENDER); + canPlaceItem = getTileData().getBoolean(CAN_PLACE_ITEM); + storageState = Block.stateById(getTileData().getInt(STORAGE_STATE_ID)); + handler.deserializeNBT(getTileData().getCompound(STORAGE_ITEM)); + direction = Direction.byName(getTileData().getString(DIRECTION)); + blockPosList.deserialize(getTileData().getList(STORAGE_BLOCK_LIST, Constants.NBT.TAG_COMPOUND)); + canPlaceItemPosList.deserialize(getTileData().getList(CAN_PLACE_ITEM_POS_LIST, Constants.NBT.TAG_COMPOUND)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AxisAlignedBB getRenderBoundingBox() { + return new AxisAlignedBB(worldPosition.offset(-9, -5, -9), worldPosition.offset(9, 5, 9)); + } + + @Override + public CompoundNBT getUpdateTag() { + return this.save(new CompoundNBT()); + } + + @Nullable + @Override + public SUpdateTileEntityPacket getUpdatePacket() { + return new SUpdateTileEntityPacket(getBlockPos(), -1, this.save(new CompoundNBT())); + } + + @Override + public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { + if (level != null) { + this.load(level.getBlockState(pkt.getPos()), pkt.getTag()); + } + } + + public void refresh() { + setChanged(); + if (level != null) { + BlockState state = level.getBlockState(worldPosition); + level.sendBlockUpdated(worldPosition, state, state, Constants.BlockFlags.DEFAULT); + } + } + + public boolean isRender() { + return isRender; + } + + public boolean isCanPlaceItem() { + return canPlaceItem; + } + + public BlockState getStorageState() { + return storageState; + } + + public PosListData getBlockPosList() { + return blockPosList; + } + + public PosListData getCanPlaceItemPosList() { + return canPlaceItemPosList; + } + + public ItemStack getStorageItem() { + if (canPlaceItem) { + return handler.getStackInSlot(0); + } + return ItemStack.EMPTY; + } + + public Direction getDirection() { + return direction; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/package-info.java new file mode 100644 index 000000000..1341c4295 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.tileentity; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/EntityCraftingHelper.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/EntityCraftingHelper.java new file mode 100644 index 000000000..e467bedff --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/EntityCraftingHelper.java @@ -0,0 +1,42 @@ +package com.github.tartaricacid.touhoulittlemaid.util; + +import com.google.gson.*; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Pair; +import net.minecraft.entity.EntityType; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.util.JSONUtils; + +import java.util.Optional; + +public final class EntityCraftingHelper { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + private static final String TYPE_TAG = "type"; + private static final String NBT_TAG = "nbt"; + + public static Pair, CompoundNBT> getEntityData(JsonObject json) { + try { + Optional> optional = EntityType.byString(JSONUtils.getAsString(json, TYPE_TAG)); + if (optional.isPresent()) { + EntityType type = optional.get(); + JsonElement element = json.get(NBT_TAG); + CompoundNBT outputData = new CompoundNBT(); + if (element == null) { + return Pair.of(type, outputData); + } + CompoundNBT readData; + if (element.isJsonObject()) { + readData = JsonToNBT.parseTag(GSON.toJson(element)); + } else { + readData = JsonToNBT.parseTag(JSONUtils.convertToString(element, NBT_TAG)); + } + outputData.put("EntityTag", readData); + return Pair.of(type, outputData); + } + throw new JsonParseException("Entity Type Tag Not Found"); + } catch (CommandSyntaxException e) { + throw new JsonSyntaxException("Invalid NBT Entry: " + e.toString()); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/PosListData.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/PosListData.java new file mode 100644 index 000000000..95c07684b --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/PosListData.java @@ -0,0 +1,35 @@ +package com.github.tartaricacid.touhoulittlemaid.util; + +import com.google.common.collect.Lists; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public final class PosListData { + private final List data = Lists.newArrayList(); + + public ListNBT serialize() { + ListNBT nbt = new ListNBT(); + for (BlockPos pos : data) { + nbt.add(NBTUtil.writeBlockPos(pos)); + } + return nbt; + } + + public void deserialize(ListNBT nbt) { + data.clear(); + for (int i = 0; i < nbt.size(); i++) { + data.add(NBTUtil.readBlockPos(nbt.getCompound(i))); + } + } + + public List getData() { + return data; + } + + public void add(BlockPos pos) { + this.data.add(pos); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 7e0fdb141..02b3c883f 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -19,4 +19,5 @@ public net.minecraft.client.renderer.model.ModelRenderer field_78805_m # childre public net.minecraft.entity.projectile.AbstractArrowEntity field_70254_i # inGround public net.minecraft.entity.LivingEntity func_70669_a(Lnet/minecraft/item/ItemStack;)V # breakItem -public net.minecraft.util.math.EntityPosWrapper field_220611_a # entity \ No newline at end of file +public net.minecraft.util.math.EntityPosWrapper field_220611_a # entity +public net.minecraft.world.gen.feature.template.Template field_204769_a # palettes \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/blockstates/altar.json b/src/main/resources/assets/touhou_little_maid/blockstates/altar.json new file mode 100644 index 000000000..e21f5d2ed --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/blockstates/altar.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "touhou_little_maid:block/altar" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/block/altar.json b/src/main/resources/assets/touhou_little_maid/models/block/altar.json new file mode 100644 index 000000000..9406a8491 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/block/altar.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "minecraft:block/oak_planks" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/textures/entity/altar.png b/src/main/resources/assets/touhou_little_maid/textures/entity/altar.png new file mode 100644 index 000000000..dd9a1d36a Binary files /dev/null and b/src/main/resources/assets/touhou_little_maid/textures/entity/altar.png differ diff --git a/src/main/resources/data/touhou_little_maid/recipes/altar/craft_explosion_protect_bauble.json b/src/main/resources/data/touhou_little_maid/recipes/altar/craft_explosion_protect_bauble.json new file mode 100644 index 000000000..98e3a1b4a --- /dev/null +++ b/src/main/resources/data/touhou_little_maid/recipes/altar/craft_explosion_protect_bauble.json @@ -0,0 +1,28 @@ +{ + "type": "touhou_little_maid:altar_crafting", + "output": { + "type": "minecraft:item", + "nbt": "{Item:{id:\"touhou_little_maid:explosion_protect_bauble\",Count:1b,tag:{Damage:0}}}" + }, + "power": 0.2, + "ingredients": [ + { + "item": "minecraft:nether_wart" + }, + { + "tag": "forge:dyes/orange" + }, + { + "tag": "forge:obsidian" + }, + { + "tag": "forge:obsidian" + }, + { + "tag": "forge:obsidian" + }, + { + "tag": "forge:obsidian" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/touhou_little_maid/structures/altar_east.nbt b/src/main/resources/data/touhou_little_maid/structures/altar_east.nbt new file mode 100644 index 000000000..8d8f30814 Binary files /dev/null and b/src/main/resources/data/touhou_little_maid/structures/altar_east.nbt differ diff --git a/src/main/resources/data/touhou_little_maid/structures/altar_north.nbt b/src/main/resources/data/touhou_little_maid/structures/altar_north.nbt new file mode 100644 index 000000000..4e7a62c95 Binary files /dev/null and b/src/main/resources/data/touhou_little_maid/structures/altar_north.nbt differ diff --git a/src/main/resources/data/touhou_little_maid/structures/altar_south.nbt b/src/main/resources/data/touhou_little_maid/structures/altar_south.nbt new file mode 100644 index 000000000..c0dd7c8bf Binary files /dev/null and b/src/main/resources/data/touhou_little_maid/structures/altar_south.nbt differ diff --git a/src/main/resources/data/touhou_little_maid/structures/altar_west.nbt b/src/main/resources/data/touhou_little_maid/structures/altar_west.nbt new file mode 100644 index 000000000..f5f4b2924 Binary files /dev/null and b/src/main/resources/data/touhou_little_maid/structures/altar_west.nbt differ