From 8df61799f8965e04a292098dfe3b14e712aa8bde Mon Sep 17 00:00:00 2001 From: thepigcat Date: Sun, 17 Nov 2024 01:58:48 +0100 Subject: [PATCH] more work on drill and sword proof of concept --- .../com/leclowndu93150/carbort/Carbort.java | 13 +- .../leclowndu93150/carbort/CarbortClient.java | 21 + .../blockentities/ContainerBlockEntity.java | 374 ++++++++++++++++++ .../carbort/api/blocks/ContainerBlock.java | 67 ++++ .../api/blocks/RotatableContainerBlock.java | 26 ++ .../carbort/api/capabilities/IOActions.java | 8 + .../api/capabilities/SidedEnergyStorage.java | 40 ++ .../api/capabilities/SidedFluidHandler.java | 50 +++ .../api/capabilities/SidedItemHandler.java | 45 +++ .../client/models/BedrockDrillHeadModel.java | 30 ++ .../blockentities/BedrockDrillBER.java | 42 ++ .../content/blockentities/BedrockDrillBE.java | 25 ++ .../SmileyCloudBlockEntity.java | 2 +- .../content/blocks/BedrockDrillBlock.java | 24 +- .../carbort/registries/CBBlockEntities.java | 8 +- .../carbort/registries/CBItems.java | 13 +- .../carbort/models/block/bedrock_drill.json | 310 ++++++++------- .../carbort/models/item/iron_great_sword.json | 21 + .../models/item/iron_great_sword_gui.json | 6 + .../item/iron_great_sword_handheld.json | 33 ++ .../carbort/textures/block/bedrock_drill.png | Bin 408 -> 419 bytes .../textures/block/bedrock_drill_side.png | Bin 274 -> 295 bytes .../textures/block/bedrock_drill_top.png | Bin 518 -> 385 bytes .../textures/item/iron_great_sword.png | Bin 0 -> 396 bytes .../item/iron_great_sword_ender_eye.png | Bin 0 -> 548 bytes .../textures/item/iron_great_sword_gui.png | Bin 0 -> 273 bytes .../carbort/textures/item/tormented_soul.png | Bin 346 -> 344 bytes 27 files changed, 986 insertions(+), 172 deletions(-) create mode 100644 src/main/java/com/leclowndu93150/carbort/CarbortClient.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/blockentities/ContainerBlockEntity.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/blocks/ContainerBlock.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/blocks/RotatableContainerBlock.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/capabilities/IOActions.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedEnergyStorage.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedFluidHandler.java create mode 100644 src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedItemHandler.java create mode 100644 src/main/java/com/leclowndu93150/carbort/client/models/BedrockDrillHeadModel.java create mode 100644 src/main/java/com/leclowndu93150/carbort/client/renderer/blockentities/BedrockDrillBER.java create mode 100644 src/main/java/com/leclowndu93150/carbort/content/blockentities/BedrockDrillBE.java rename src/main/java/com/leclowndu93150/carbort/content/{blockEntities => blockentities}/SmileyCloudBlockEntity.java (87%) create mode 100644 src/main/resources/assets/carbort/models/item/iron_great_sword.json create mode 100644 src/main/resources/assets/carbort/models/item/iron_great_sword_gui.json create mode 100644 src/main/resources/assets/carbort/models/item/iron_great_sword_handheld.json create mode 100644 src/main/resources/assets/carbort/textures/item/iron_great_sword.png create mode 100644 src/main/resources/assets/carbort/textures/item/iron_great_sword_ender_eye.png create mode 100644 src/main/resources/assets/carbort/textures/item/iron_great_sword_gui.png diff --git a/src/main/java/com/leclowndu93150/carbort/Carbort.java b/src/main/java/com/leclowndu93150/carbort/Carbort.java index c115b5e..48c29a1 100644 --- a/src/main/java/com/leclowndu93150/carbort/Carbort.java +++ b/src/main/java/com/leclowndu93150/carbort/Carbort.java @@ -4,6 +4,8 @@ import com.leclowndu93150.carbort.registries.*; import com.mojang.logging.LogUtils; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.ModContainer; @@ -11,6 +13,7 @@ import net.neoforged.fml.config.ModConfig; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.neoforge.client.event.ClientTickEvent; +import net.neoforged.neoforge.client.event.ModelEvent; import net.neoforged.neoforge.event.tick.PlayerTickEvent; import net.neoforged.neoforge.event.tick.ServerTickEvent; import org.slf4j.Logger; @@ -23,6 +26,7 @@ public class Carbort { public Carbort(IEventBus modEventBus, ModContainer modContainer) { new CBFoods(); + CBTabs.CREATIVE_MODE_TABS.register(modEventBus); CBItems.ITEMS.register(modEventBus); CBBlocks.BLOCKS.register(modEventBus); @@ -31,12 +35,13 @@ public Carbort(IEventBus modEventBus, ModContainer modContainer) { CBMobEffects.POTIONS.register(modEventBus); CBDataComponents.DATA_COMPONENTS.register(modEventBus); CBMenus.MENUS.register(modEventBus); - modEventBus.addListener(this::commonSetup); + + modEventBus.addListener(this::registerBakedModels); + modContainer.registerConfig(ModConfig.Type.COMMON, CarbortConfig.SPEC); } - - private void commonSetup(final FMLCommonSetupEvent event) { - LOGGER.info("I hope i did things right."); + private void registerBakedModels(ModelEvent.RegisterAdditional event) { + event.register(ModelResourceLocation.standalone(ResourceLocation.fromNamespaceAndPath(MODID, "block/bedrock_drill_head"))); } } diff --git a/src/main/java/com/leclowndu93150/carbort/CarbortClient.java b/src/main/java/com/leclowndu93150/carbort/CarbortClient.java new file mode 100644 index 0000000..6068cf6 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/CarbortClient.java @@ -0,0 +1,21 @@ +package com.leclowndu93150.carbort; + +import com.leclowndu93150.carbort.client.renderer.blockentities.BedrockDrillBER; +import com.leclowndu93150.carbort.registries.CBBlockEntities; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; + +@Mod(value = CarbortClient.MODID, dist = Dist.CLIENT) +public class CarbortClient { + public static final String MODID = "carbort"; + + public CarbortClient(IEventBus modEventBus) { + modEventBus.addListener(this::registerBERs); + } + + private void registerBERs(EntityRenderersEvent.RegisterRenderers event) { + event.registerBlockEntityRenderer(CBBlockEntities.BEDROCK_DRILL.get(), BedrockDrillBER::new); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/api/blockentities/ContainerBlockEntity.java b/src/main/java/com/leclowndu93150/carbort/api/blockentities/ContainerBlockEntity.java new file mode 100644 index 0000000..98d3c73 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/blockentities/ContainerBlockEntity.java @@ -0,0 +1,374 @@ +package com.leclowndu93150.carbort.api.blockentities; + +import com.google.common.collect.ImmutableMap; +import com.leclowndu93150.carbort.Carbort; +import com.leclowndu93150.carbort.api.capabilities.IOActions; +import com.leclowndu93150.carbort.api.capabilities.SidedEnergyStorage; +import com.leclowndu93150.carbort.api.capabilities.SidedFluidHandler; +import com.leclowndu93150.carbort.api.capabilities.SidedItemHandler; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.Containers; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.neoforged.neoforge.capabilities.BlockCapability; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.energy.EnergyStorage; +import net.neoforged.neoforge.energy.IEnergyStorage; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemStackHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public abstract class ContainerBlockEntity extends BlockEntity { + private @Nullable ItemStackHandler itemHandler; + private @Nullable FluidTank fluidTank; + private @Nullable EnergyStorage energyStorage; + + public ContainerBlockEntity(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { + super(blockEntityType, blockPos, blockState); + } + + public void commonTick() { + } + + public IItemHandler getItemHandler() { + return itemHandler; + } + + public IFluidHandler getFluidHandler() { + return fluidTank; + } + + public IEnergyStorage getEnergyStorage() { + return energyStorage; + } + + protected ItemStackHandler getItemStackHandler() { + return itemHandler; + } + + protected @Nullable FluidTank getFluidTank() { + return fluidTank; + } + + protected EnergyStorage getEnergyStorageImpl() { + return energyStorage; + } + + @Override + protected final void loadAdditional(@NotNull CompoundTag nbt, HolderLookup.@NotNull Provider provider) { + super.loadAdditional(nbt, provider); + if (this.getFluidTank() != null) + this.getFluidTank().readFromNBT(provider, nbt.getCompound("fluid_tank")); + if (this.getItemStackHandler() != null) + this.getItemStackHandler().deserializeNBT(provider, nbt.getCompound("itemhandler")); + if (this.getEnergyStorageImpl() != null) + this.getEnergyStorageImpl().deserializeNBT(provider, nbt.get("energy_storage")); + loadData(nbt, provider); + } + + @Override + protected final void saveAdditional(@NotNull CompoundTag nbt, HolderLookup.@NotNull Provider provider) { + super.saveAdditional(nbt, provider); + if (getFluidTank() != null) { + CompoundTag tag = new CompoundTag(); + getFluidTank().writeToNBT(provider, tag); + nbt.put("fluid_tank", tag); + } + if (getItemStackHandler() != null) + nbt.put("itemhandler", getItemStackHandler().serializeNBT(provider)); + if (getEnergyStorageImpl() != null) + nbt.put("energy_storage", getEnergyStorageImpl().serializeNBT(provider)); + saveData(nbt, provider); + } + + protected void loadData(CompoundTag tag, HolderLookup.Provider provider) { + } + + protected void saveData(CompoundTag tag, HolderLookup.Provider provider) { + } + + protected final void addItemHandler(int slots) { + addItemHandler(slots, (slot, itemStack) -> true); + } + + protected final void addItemHandler(int slots, int slotLimit) { + addItemHandler(slots, slotLimit, (slot, itemStack) -> true); + } + + protected final void addItemHandler(int slots, BiPredicate validation) { + addItemHandler(slots, 64, validation); + } + + protected final void addItemHandler(int slots, int slotLimit, BiPredicate validation) { + this.itemHandler = new ItemStackHandler(slots) { + @Override + protected void onContentsChanged(int slot) { + update(); + setChanged(); + onItemsChanged(slot); + invalidateCapabilities(); + } + + @Override + public boolean isItemValid(int slot, @NotNull ItemStack stack) { + return validation.test(slot, stack); + } + + @Override + public int getSlotLimit(int slot) { + return slotLimit; + } + + @Override + public int getSlots() { + return slots; + } + }; + } + + protected final void addFluidTank(int capacityInMb) { + addFluidTank(capacityInMb, ignored -> true); + } + + protected final void addFluidTank(int capacityInMb, Predicate validation) { + this.fluidTank = new FluidTank(capacityInMb) { + @Override + protected void onContentsChanged() { + update(); + setChanged(); + onFluidChanged(); + } + + @Override + public boolean isFluidValid(FluidStack stack) { + return validation.test(stack); + } + }; + } + + protected final void addEnergyStorage(int energyCapacity) { + this.energyStorage = new EnergyStorage(energyCapacity) { + @Override + public int receiveEnergy(int toReceive, boolean simulate) { + int receivedEnergy = super.receiveEnergy(toReceive, simulate); + if (receivedEnergy > 0) { + update(); + setChanged(); + ContainerBlockEntity.this.onEnergyChanged(); + } + return receivedEnergy; + } + + @Override + public int extractEnergy(int toExtract, boolean simulate) { + int extractedEnergy = super.extractEnergy(toExtract, simulate); + if (extractedEnergy > 0) { + update(); + setChanged(); + ContainerBlockEntity.this.onEnergyChanged(); + } + return extractedEnergy; + } + }; + } + + private void update() { + if (!level.isClientSide()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3); + } + } + + protected void onItemsChanged(int slot) { + } + + protected void onFluidChanged() { + } + + public void onEnergyChanged() { + } + + public void drop() { + ItemStack[] stacks = getItemHandlerStacks(); + if (stacks != null) { + SimpleContainer inventory = new SimpleContainer(stacks); + Containers.dropContents(this.level, this.worldPosition, inventory); + } + } + + public @Nullable ItemStack[] getItemHandlerStacks() { + IItemHandler itemStackHandler = getItemHandler(); + + if (itemStackHandler == null) return null; + + ItemStack[] itemStacks = new ItemStack[itemStackHandler.getSlots()]; + for (int i = 0; i < itemStackHandler.getSlots(); i++) { + itemStacks[i] = itemStackHandler.getStackInSlot(i); + } + return itemStacks; + } + + public List getItemHandlerStacksList() { + IItemHandler itemStackHandler = getItemHandler(); + + if (itemStackHandler == null) return null; + + int slots = itemStackHandler.getSlots(); + ObjectList itemStacks = new ObjectArrayList<>(slots); + for (int i = 0; i < slots; i++) { + ItemStack stack = itemStackHandler.getStackInSlot(i); + if (!stack.isEmpty()) { + itemStacks.add(stack); + } + } + return itemStacks; + } + + public T getHandlerOnSide(BlockCapability capability, SidedHandlerSupplier handlerSupplier, Direction direction, T baseHandler) { + if (direction == null) { + return baseHandler; + } + + Map> ioPorts = getSidedInteractions(capability); + if (ioPorts.containsKey(direction)) { + if (direction == Direction.UP || direction == Direction.DOWN) { + return handlerSupplier.get(baseHandler, ioPorts.get(direction)); + } + + if (this.getBlockState().hasProperty(BlockStateProperties.FACING)) { + Direction localDir = this.getBlockState().getValue(BlockStateProperties.FACING); + + return getCapOnSide(handlerSupplier, direction, baseHandler, ioPorts, localDir); + } + + if (this.getBlockState().hasProperty(BlockStateProperties.HORIZONTAL_FACING)) { + Direction localDir = this.getBlockState().getValue(BlockStateProperties.HORIZONTAL_FACING); + + return getCapOnSide(handlerSupplier, direction, baseHandler, ioPorts, localDir); + } + + Carbort.LOGGER.warn("Sided io for non facing block"); + } + + return null; + } + + @Nullable + private T getCapOnSide(SidedHandlerSupplier handlerSupplier, Direction direction, T baseHandler, Map> ioPorts, Direction localDir) { + return switch (localDir) { + case NORTH -> handlerSupplier.get(baseHandler, ioPorts.get(direction.getOpposite())); + case EAST -> handlerSupplier.get(baseHandler, ioPorts.get(direction.getClockWise())); + case SOUTH, DOWN, UP -> handlerSupplier.get(baseHandler, ioPorts.get(direction)); + case WEST -> handlerSupplier.get(baseHandler, ioPorts.get(direction.getCounterClockWise())); + }; + } + + public IItemHandler getItemHandlerOnSide(Direction direction) { + return getHandlerOnSide( + Capabilities.ItemHandler.BLOCK, + SidedItemHandler::new, + direction, + getItemHandler() + ); + } + + public IFluidHandler getFluidHandlerOnSide(Direction direction) { + return getHandlerOnSide( + Capabilities.FluidHandler.BLOCK, + SidedFluidHandler::new, + direction, + getFluidHandler() + ); + } + + public IEnergyStorage getEnergyStorageOnSide(Direction direction) { + return getHandlerOnSide( + Capabilities.EnergyStorage.BLOCK, + SidedEnergyStorage::new, + direction, + getEnergyStorage() + ); + } + + /** + * Get the input/output config for the blockenitity. + * If directions are not defined in the map, they are assumed to be {@link IOActions#NONE} and do not affect any slot. + * + * @return Map of directions that each map to a pair that defines the IOAction as well as the tanks that are affected. Return an empty map if you do not have an itemhandler + */ + public abstract Map> getSidedInteractions(BlockCapability capability); + + public static ImmutableMap> allBoth(int ...slots) { + return ImmutableMap.of( + Direction.NORTH, Pair.of(IOActions.BOTH, slots), + Direction.EAST, Pair.of(IOActions.BOTH, slots), + Direction.SOUTH, Pair.of(IOActions.BOTH, slots), + Direction.WEST, Pair.of(IOActions.BOTH, slots), + Direction.UP, Pair.of(IOActions.BOTH, slots), + Direction.DOWN, Pair.of(IOActions.BOTH, slots) + ); + } + public static ImmutableMap> allInsert(int ...slots) { + return ImmutableMap.of( + Direction.NORTH, Pair.of(IOActions.INSERT, slots), + Direction.EAST, Pair.of(IOActions.INSERT, slots), + Direction.SOUTH, Pair.of(IOActions.INSERT, slots), + Direction.WEST, Pair.of(IOActions.INSERT, slots), + Direction.UP, Pair.of(IOActions.INSERT, slots), + Direction.DOWN, Pair.of(IOActions.INSERT, slots) + ); + } + public static ImmutableMap> allExtract(int ...slots) { + return ImmutableMap.of( + Direction.NORTH, Pair.of(IOActions.EXTRACT, slots), + Direction.EAST, Pair.of(IOActions.EXTRACT, slots), + Direction.SOUTH, Pair.of(IOActions.EXTRACT, slots), + Direction.WEST, Pair.of(IOActions.EXTRACT, slots), + Direction.UP, Pair.of(IOActions.EXTRACT, slots), + Direction.DOWN, Pair.of(IOActions.EXTRACT, slots) + ); + } + + @Nullable + @Override + public Packet getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public @NotNull CompoundTag getUpdateTag(HolderLookup.Provider provider) { + return saveWithoutMetadata(provider); + } + + @Override + public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt, HolderLookup.Provider lookupProvider) { + super.onDataPacket(net, pkt, lookupProvider); + } + + @FunctionalInterface + public interface SidedHandlerSupplier { + T get(T handler, Pair supportedActions); + } +} \ No newline at end of file diff --git a/src/main/java/com/leclowndu93150/carbort/api/blocks/ContainerBlock.java b/src/main/java/com/leclowndu93150/carbort/api/blocks/ContainerBlock.java new file mode 100644 index 0000000..4888337 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/blocks/ContainerBlock.java @@ -0,0 +1,67 @@ +package com.leclowndu93150.carbort.api.blocks; + +import com.leclowndu93150.carbort.api.blockentities.ContainerBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class ContainerBlock extends BaseEntityBlock { + public ContainerBlock(Properties properties) { + super(properties); + } + + public abstract boolean tickingEnabled(); + + public abstract BlockEntityType getBlockEntityType(); + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return getBlockEntityType().create(blockPos, blockState); + } + + @Override + public @NotNull RenderShape getRenderShape(BlockState p_49232_) { + return RenderShape.MODEL; + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { + if (!tickingEnabled()) return null; + + return createTickerHelper(blockEntityType, getBlockEntityType(), (level1, pos1, state1, entity1) -> entity1.commonTick()); + } + + @Override + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + BlockEntity be = level.getBlockEntity(pos); + if (be instanceof ContainerBlockEntity containerBE) { + if (!state.is(newState.getBlock())) { + containerBE.drop(); + } + } + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + protected @NotNull InteractionResult useWithoutItem(BlockState p_60503_, Level p_60504_, BlockPos p_60505_, Player p_60506_, BlockHitResult p_60508_) { + BlockEntity blockEntity = p_60504_.getBlockEntity(p_60505_); + if (blockEntity instanceof MenuProvider menuProvider) { + p_60506_.openMenu(menuProvider, p_60505_); + return InteractionResult.SUCCESS; + } + return super.useWithoutItem(p_60503_, p_60504_, p_60505_, p_60506_, p_60508_); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/api/blocks/RotatableContainerBlock.java b/src/main/java/com/leclowndu93150/carbort/api/blocks/RotatableContainerBlock.java new file mode 100644 index 0000000..c9168e1 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/blocks/RotatableContainerBlock.java @@ -0,0 +1,26 @@ +package com.leclowndu93150.carbort.api.blocks; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import org.jetbrains.annotations.Nullable; + +public abstract class RotatableContainerBlock extends ContainerBlock { + public RotatableContainerBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_FACING, Direction.NORTH)); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + super.createBlockStateDefinition(builder.add(BlockStateProperties.HORIZONTAL_FACING)); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_FACING, context.getHorizontalDirection().getOpposite()); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/api/capabilities/IOActions.java b/src/main/java/com/leclowndu93150/carbort/api/capabilities/IOActions.java new file mode 100644 index 0000000..79abc35 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/capabilities/IOActions.java @@ -0,0 +1,8 @@ +package com.leclowndu93150.carbort.api.capabilities; + +public enum IOActions { + INSERT, + EXTRACT, + BOTH, + NONE, +} \ No newline at end of file diff --git a/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedEnergyStorage.java b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedEnergyStorage.java new file mode 100644 index 0000000..a1cffee --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedEnergyStorage.java @@ -0,0 +1,40 @@ +package com.leclowndu93150.carbort.api.capabilities; +import it.unimi.dsi.fastutil.Pair; +import net.neoforged.neoforge.energy.IEnergyStorage; + +public record SidedEnergyStorage(IEnergyStorage innerHandler, + IOActions action) implements IEnergyStorage { + public SidedEnergyStorage(IEnergyStorage innerHandler, Pair actionSlotsPair) { + this(innerHandler, actionSlotsPair != null ? actionSlotsPair.left() : IOActions.NONE); + } + + @Override + public int receiveEnergy(int toReceive, boolean simulate) { + return action == IOActions.INSERT || action == IOActions.BOTH ? innerHandler.receiveEnergy(toReceive, simulate) : 0; + } + + @Override + public int extractEnergy(int toExtract, boolean simulate) { + return action == IOActions.EXTRACT || action == IOActions.BOTH ? innerHandler.extractEnergy(toExtract, simulate) : 0; + } + + @Override + public int getEnergyStored() { + return innerHandler.getEnergyStored(); + } + + @Override + public int getMaxEnergyStored() { + return innerHandler.getMaxEnergyStored(); + } + + @Override + public boolean canExtract() { + return action == IOActions.EXTRACT || action == IOActions.BOTH; + } + + @Override + public boolean canReceive() { + return action == IOActions.INSERT || action == IOActions.BOTH; + } +} \ No newline at end of file diff --git a/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedFluidHandler.java b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedFluidHandler.java new file mode 100644 index 0000000..89fddac --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedFluidHandler.java @@ -0,0 +1,50 @@ +package com.leclowndu93150.carbort.api.capabilities; + +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.IntList; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import org.jetbrains.annotations.NotNull; + +public record SidedFluidHandler(IFluidHandler innerHandler, + IOActions action, + IntList tanks) implements IFluidHandler { + public SidedFluidHandler(IFluidHandler innerHandler, Pair actionSlotsPair) { + this(innerHandler, actionSlotsPair != null ? actionSlotsPair.left() : IOActions.NONE, actionSlotsPair != null ? IntList.of(actionSlotsPair.right()) : IntList.of()); + } + + @Override + public int getTanks() { + return innerHandler.getTanks(); + } + + @Override + public @NotNull FluidStack getFluidInTank(int tank) { + return innerHandler.getFluidInTank(tank); + } + + @Override + public int getTankCapacity(int tank) { + return innerHandler.getTankCapacity(tank); + } + + @Override + public boolean isFluidValid(int tank, @NotNull FluidStack stack) { + return action == IOActions.INSERT || action == IOActions.BOTH && tanks.contains(tank) && innerHandler.isFluidValid(tank, stack); + } + + @Override + public int fill(FluidStack resource, FluidAction fAction) { + return action == IOActions.INSERT || action == IOActions.BOTH ? innerHandler.fill(resource, fAction) : 0; + } + + @Override + public @NotNull FluidStack drain(FluidStack resource, FluidAction fAction) { + return action == IOActions.EXTRACT || action == IOActions.BOTH ? innerHandler.drain(resource, fAction) : FluidStack.EMPTY; + } + + @Override + public @NotNull FluidStack drain(int maxDrain, FluidAction fAction) { + return action == IOActions.EXTRACT || action == IOActions.BOTH ? innerHandler.drain(maxDrain, fAction) : FluidStack.EMPTY; + } +} \ No newline at end of file diff --git a/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedItemHandler.java b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedItemHandler.java new file mode 100644 index 0000000..adac957 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/api/capabilities/SidedItemHandler.java @@ -0,0 +1,45 @@ +package com.leclowndu93150.carbort.api.capabilities; + +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.items.IItemHandler; +import org.jetbrains.annotations.NotNull; + +public record SidedItemHandler(IItemHandler innerHandler, + IOActions action, + IntList slots) implements IItemHandler { + public SidedItemHandler(IItemHandler innerHandler, Pair actionSlotsPair) { + this(innerHandler, actionSlotsPair != null ? actionSlotsPair.left() : IOActions.NONE, actionSlotsPair != null ? IntList.of(actionSlotsPair.right()) : IntList.of()); + } + + @Override + public int getSlots() { + return innerHandler.getSlots(); + } + + @Override + public @NotNull ItemStack getStackInSlot(int i) { + return innerHandler.getStackInSlot(i); + } + + @Override + public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack itemStack, boolean simulate) { + return action == IOActions.INSERT || action == IOActions.BOTH && slots.contains(slot) ? innerHandler.insertItem(slot, itemStack, simulate) : itemStack; + } + + @Override + public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) { + return action == IOActions.EXTRACT || action == IOActions.BOTH && slots.contains(slot) ? innerHandler.extractItem(slot, amount, simulate) : ItemStack.EMPTY; + } + + @Override + public int getSlotLimit(int i) { + return innerHandler.getSlotLimit(i); + } + + @Override + public boolean isItemValid(int slot, @NotNull ItemStack itemStack) { + return action == IOActions.INSERT || action == IOActions.BOTH && slots.contains(slot) && innerHandler.isItemValid(slot, itemStack); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/client/models/BedrockDrillHeadModel.java b/src/main/java/com/leclowndu93150/carbort/client/models/BedrockDrillHeadModel.java new file mode 100644 index 0000000..c557d38 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/client/models/BedrockDrillHeadModel.java @@ -0,0 +1,30 @@ +package com.leclowndu93150.carbort.client.models; + +import net.minecraft.client.model.Model; +import net.minecraft.client.model.geom.ModelPart; + +public class BedrockDrillHeadModel {}// extends Model { +// public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(new ResourceLocation("modid", "custommodel"), "main"); +// private final ModelPart drill_head; +// +// public BedrockDrillHeadModel(ModelPart root) { +// this.drill_head = root.getChild("drill_head"); +// } +// +// public static LayerDefinition createBodyLayer() { +// MeshDefinition meshdefinition = new MeshDefinition(); +// PartDefinition partdefinition = meshdefinition.getRoot(); +// +// PartDefinition drill_head = partdefinition.addOrReplaceChild("drill_head", CubeListBuilder.create().texOffs(0, 0).addBox(-2.0F, -14.0F, -2.0F, 4.0F, 20.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 16.0F, 0.0F)); +// +// PartDefinition cube_r1 = drill_head.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(16, 14).addBox(-2.0F, 2.0F, -1.0F, 4.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 1.0503F, 5.5355F, -0.7854F, 0.0F, 0.0F)); +// +// PartDefinition cube_r2 = drill_head.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(16, 6).addBox(-1.0F, 2.0F, -2.0F, 2.0F, 4.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.5355F, 1.0503F, 0.0F, 0.0F, 0.0F, -0.7854F)); +// +// PartDefinition cube_r3 = drill_head.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 24).addBox(-1.0F, 2.0F, -2.0F, 2.0F, 4.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(5.5355F, 1.0503F, 0.0F, 0.0F, 0.0F, 0.7854F)); +// +// PartDefinition cube_r4 = drill_head.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(16, 0).addBox(-2.0F, -1.0F, 2.0F, 4.0F, 2.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 1.0503F, -5.5355F, -0.7854F, 0.0F, 0.0F)); +// +// return LayerDefinition.create(meshdefinition, 32, 32); +// } +//} diff --git a/src/main/java/com/leclowndu93150/carbort/client/renderer/blockentities/BedrockDrillBER.java b/src/main/java/com/leclowndu93150/carbort/client/renderer/blockentities/BedrockDrillBER.java new file mode 100644 index 0000000..1ff1e53 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/client/renderer/blockentities/BedrockDrillBER.java @@ -0,0 +1,42 @@ +package com.leclowndu93150.carbort.client.renderer.blockentities; + +import com.leclowndu93150.carbort.Carbort; +import com.leclowndu93150.carbort.content.blockentities.BedrockDrillBE; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.client.model.data.ModelData; + +public class BedrockDrillBER implements BlockEntityRenderer { + private int rotation = 0; + + public BedrockDrillBER(BlockEntityRendererProvider.Context context) { + } + + @Override + public void render(BedrockDrillBE blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) { + if (rotation < 359) { + rotation++; + } else { + rotation = 0; + } + + Minecraft mc = Minecraft.getInstance(); + BakedModel model = mc.getModelManager().getModel(ModelResourceLocation.standalone(ResourceLocation.fromNamespaceAndPath(Carbort.MODID, "block/bedrock_drill_head"))); + poseStack.pushPose(); + { + poseStack.translate(0.5, 0, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(rotation)); + poseStack.translate(-0.5, 0, -0.5); + mc.getBlockRenderer().getModelRenderer().renderModel(poseStack.last(), bufferSource.getBuffer(RenderType.SOLID), blockEntity.getBlockState(), model, 255, 255, 255, packedLight, packedOverlay, ModelData.EMPTY, RenderType.SOLID); + } + poseStack.popPose(); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/content/blockentities/BedrockDrillBE.java b/src/main/java/com/leclowndu93150/carbort/content/blockentities/BedrockDrillBE.java new file mode 100644 index 0000000..ede1fc1 --- /dev/null +++ b/src/main/java/com/leclowndu93150/carbort/content/blockentities/BedrockDrillBE.java @@ -0,0 +1,25 @@ +package com.leclowndu93150.carbort.content.blockentities; + +import com.leclowndu93150.carbort.api.blockentities.ContainerBlockEntity; +import com.leclowndu93150.carbort.api.capabilities.IOActions; +import com.leclowndu93150.carbort.registries.CBBlockEntities; +import it.unimi.dsi.fastutil.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.capabilities.BlockCapability; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class BedrockDrillBE extends ContainerBlockEntity { + public BedrockDrillBE(BlockPos pos, BlockState blockState) { + super(CBBlockEntities.BEDROCK_DRILL.get(), pos, blockState); + } + + @Override + public Map> getSidedInteractions(BlockCapability capability) { + return Map.of(); + } +} diff --git a/src/main/java/com/leclowndu93150/carbort/content/blockEntities/SmileyCloudBlockEntity.java b/src/main/java/com/leclowndu93150/carbort/content/blockentities/SmileyCloudBlockEntity.java similarity index 87% rename from src/main/java/com/leclowndu93150/carbort/content/blockEntities/SmileyCloudBlockEntity.java rename to src/main/java/com/leclowndu93150/carbort/content/blockentities/SmileyCloudBlockEntity.java index 0fac465..e8fb1c8 100644 --- a/src/main/java/com/leclowndu93150/carbort/content/blockEntities/SmileyCloudBlockEntity.java +++ b/src/main/java/com/leclowndu93150/carbort/content/blockentities/SmileyCloudBlockEntity.java @@ -1,4 +1,4 @@ -package com.leclowndu93150.carbort.content.blockEntities; +package com.leclowndu93150.carbort.content.blockentities; import com.leclowndu93150.carbort.registries.CBBlockEntities; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/leclowndu93150/carbort/content/blocks/BedrockDrillBlock.java b/src/main/java/com/leclowndu93150/carbort/content/blocks/BedrockDrillBlock.java index 5651316..5efc84c 100644 --- a/src/main/java/com/leclowndu93150/carbort/content/blocks/BedrockDrillBlock.java +++ b/src/main/java/com/leclowndu93150/carbort/content/blocks/BedrockDrillBlock.java @@ -1,19 +1,24 @@ package com.leclowndu93150.carbort.content.blocks; +import com.leclowndu93150.carbort.api.blockentities.ContainerBlockEntity; +import com.leclowndu93150.carbort.api.blocks.RotatableContainerBlock; +import com.leclowndu93150.carbort.registries.CBBlockEntities; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import java.util.stream.Stream; -public class BedrockDrillBlock extends HorizontalDirectionalBlock { +public class BedrockDrillBlock extends RotatableContainerBlock { public static final VoxelShape SHAPE = Stream.of( Block.box(0, 0, 0, 4, 10, 4), Block.box(0, 0, 12, 4, 10, 16), @@ -34,17 +39,22 @@ public BedrockDrillBlock(Properties properties) { } @Override - protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { - return SHAPE; + public boolean tickingEnabled() { + return false; } @Override - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - super.createBlockStateDefinition(builder.add(FACING)); + public BlockEntityType getBlockEntityType() { + return CBBlockEntities.BEDROCK_DRILL.get(); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; } @Override - protected MapCodec codec() { + protected MapCodec codec() { return simpleCodec(BedrockDrillBlock::new); } } diff --git a/src/main/java/com/leclowndu93150/carbort/registries/CBBlockEntities.java b/src/main/java/com/leclowndu93150/carbort/registries/CBBlockEntities.java index a79c477..4eacf0d 100644 --- a/src/main/java/com/leclowndu93150/carbort/registries/CBBlockEntities.java +++ b/src/main/java/com/leclowndu93150/carbort/registries/CBBlockEntities.java @@ -1,7 +1,8 @@ package com.leclowndu93150.carbort.registries; import com.leclowndu93150.carbort.Carbort; -import com.leclowndu93150.carbort.content.blockEntities.SmileyCloudBlockEntity; +import com.leclowndu93150.carbort.content.blockentities.BedrockDrillBE; +import com.leclowndu93150.carbort.content.blockentities.SmileyCloudBlockEntity; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.neoforge.registries.DeferredRegister; @@ -11,5 +12,8 @@ public final class CBBlockEntities { public static final DeferredRegister> REGISTER = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, Carbort.MODID); - public static final Supplier> SMILEY_CLOUD = REGISTER.register("smiley_cloud", () -> BlockEntityType.Builder.of(SmileyCloudBlockEntity::new, CBBlocks.SMILEY_CLOUD.get()).build(null)); + public static final Supplier> SMILEY_CLOUD = REGISTER.register("smiley_cloud", + () -> BlockEntityType.Builder.of(SmileyCloudBlockEntity::new, CBBlocks.SMILEY_CLOUD.get()).build(null)); + public static final Supplier> BEDROCK_DRILL = REGISTER.register("bedrock_drill", + () -> BlockEntityType.Builder.of(BedrockDrillBE::new, CBBlocks.BEDROCK_DRILL.get()).build(null)); } diff --git a/src/main/java/com/leclowndu93150/carbort/registries/CBItems.java b/src/main/java/com/leclowndu93150/carbort/registries/CBItems.java index 52bf4cd..6069731 100644 --- a/src/main/java/com/leclowndu93150/carbort/registries/CBItems.java +++ b/src/main/java/com/leclowndu93150/carbort/registries/CBItems.java @@ -5,9 +5,7 @@ import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.food.FoodProperties; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.*; import net.neoforged.neoforge.registries.DeferredItem; import net.neoforged.neoforge.registries.DeferredRegister; @@ -52,9 +50,12 @@ public final class CBItems { .build()))); public static final DeferredItem TORMENTED_SOUL = ITEMS.register("tormented_soul", () -> new Item(new Item.Properties())); - public static final DeferredItem UNSTABLE_INGOT = ITEMS.register("unstable_ingot", () -> new UnstableIngotItem(new Item.Properties())); + public static final DeferredItem UNSTABLE_INGOT = ITEMS.register("unstable_ingot", () -> new UnstableIngotItem(new Item.Properties())); - public static final DeferredItem EMP = ITEMS.register("emp", () -> new EmpItem(new Item.Properties())); + public static final DeferredItem EMP = ITEMS.register("emp", () -> new EmpItem(new Item.Properties())); - public static final DeferredItem DIVISION_SIGIL = ITEMS.register("division_sigil", () -> new DivisionSigilItem(new Item.Properties())); + public static final DeferredItem DIVISION_SIGIL = ITEMS.register("division_sigil", () -> new DivisionSigilItem(new Item.Properties())); + + public static final DeferredItem IRON_GREAT_SWORD = ITEMS.register("iron_great_sword", () -> new SwordItem(Tiers.DIAMOND, new Item.Properties() + .attributes(SwordItem.createAttributes(Tiers.DIAMOND, 3, -3.2F)))); } diff --git a/src/main/resources/assets/carbort/models/block/bedrock_drill.json b/src/main/resources/assets/carbort/models/block/bedrock_drill.json index cbbbe1a..08781f5 100644 --- a/src/main/resources/assets/carbort/models/block/bedrock_drill.json +++ b/src/main/resources/assets/carbort/models/block/bedrock_drill.json @@ -8,6 +8,149 @@ "particle": "carbort:block/bedrock_drill" }, "elements": [ + { + "from": [4, 13, -3], + "to": [12, 19, -2], + "rotation": {"angle": 22.5, "axis": "x", "origin": [7, 12, -6]}, + "faces": { + "north": {"uv": [4, 10, 12, 16], "texture": "#0"}, + "east": {"uv": [4, 10, 5, 16], "texture": "#0"}, + "south": {"uv": [3.5, 5, 5.5, 6.5], "texture": "#0"}, + "west": {"uv": [11, 10, 12, 16], "texture": "#0"}, + "up": {"uv": [12, 10, 4, 11], "texture": "#0"}, + "down": {"uv": [4, 15, 12, 16], "texture": "#0"} + } + }, + { + "from": [16, 11, 4], + "to": [17, 13, 7], + "rotation": {"angle": 0, "axis": "y", "origin": [17, 11, 5]}, + "faces": { + "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "east": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 90, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "texture": "#0"} + } + }, + { + "from": [16, 11, 9], + "to": [17, 13, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [17, 11, 10]}, + "faces": { + "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "east": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 90, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "texture": "#0"} + } + }, + { + "from": [-1, 11, 9], + "to": [0, 13, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 11, 11]}, + "faces": { + "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "east": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [-1, 11, 4], + "to": [0, 13, 7], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 11, 6]}, + "faces": { + "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "east": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [9, 11, 16], + "to": [12, 13, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 11, 17]}, + "faces": { + "north": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "east": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "south": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [4, 11, 16], + "to": [7, 13, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [6, 11, 17]}, + "faces": { + "north": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, + "east": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "south": {"uv": [0, 0, 3, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 1, 2], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 1], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 1, 1, 2], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [13, 16, 14], + "to": [15, 26, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [13, 16, 13]}, + "faces": { + "north": {"uv": [13, 6, 15, 16], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, + "south": {"uv": [13, 6, 15, 16], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, + "up": {"uv": [0, 0, 0.5, 0], "texture": "#0"}, + "down": {"uv": [0, 0, 0.5, 0], "texture": "#0"} + } + }, + { + "from": [13, 26, 13], + "to": [15, 28, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [13, 22, 15]}, + "faces": { + "north": {"uv": [13, 4, 15, 6], "texture": "#0"}, + "east": {"uv": [13, 4, 15, 6], "texture": "#0"}, + "south": {"uv": [13, 4, 15, 6], "texture": "#0"}, + "west": {"uv": [13, 4, 15, 6], "texture": "#0"}, + "up": {"uv": [13, 2, 15, 4], "texture": "#0"}, + "down": {"uv": [13, 0, 15, 2], "texture": "#0"} + } + }, + { + "from": [14, 16, 13], + "to": [14, 26, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [13, 16, 15]}, + "faces": { + "north": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, + "east": {"uv": [13, 6, 15, 16], "texture": "#0"}, + "south": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, + "west": {"uv": [13, 6, 15, 16], "texture": "#0"}, + "up": {"uv": [0, 0, 0.5, 0], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0.5, 0], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [11, 16, 14], + "to": [12, 24, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [10, 16, 13]}, + "faces": { + "north": {"uv": [13, 8, 14, 16], "texture": "#0"}, + "east": {"uv": [13, 8, 14, 16], "texture": "#0"}, + "south": {"uv": [13, 8, 14, 16], "texture": "#0"}, + "west": {"uv": [13, 8, 14, 16], "texture": "#0"}, + "up": {"uv": [13, 8, 14, 16], "texture": "#0"}, + "down": {"uv": [13, 8, 14, 16], "texture": "#0"} + } + }, { "from": [0, 0, 0], "to": [4, 10, 4], @@ -55,7 +198,7 @@ "east": {"uv": [0, 12, 16, 16], "texture": "#1"}, "south": {"uv": [10, 12, 16, 16], "texture": "#1"}, "west": {"uv": [0, 11, 16, 15], "texture": "#1"}, - "up": {"uv": [6, 0, 0, 16], "texture": "#2"}, + "up": {"uv": [10, 0, 16, 16], "texture": "#2"}, "down": {"uv": [6, 0, 0, 16], "texture": "#2"} } }, @@ -81,23 +224,10 @@ "east": {"uv": [0, 12, 16, 16], "texture": "#1"}, "south": {"uv": [0, 12, 6, 16], "texture": "#1"}, "west": {"uv": [0, 12, 16, 16], "texture": "#1"}, - "up": {"uv": [16, 0, 10, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 6, 16], "texture": "#2"}, "down": {"uv": [16, 0, 10, 16], "texture": "#2"} } }, - { - "from": [4, 13, -3], - "to": [12, 19, -2], - "rotation": {"angle": 22.5, "axis": "x", "origin": [7, 12, -6]}, - "faces": { - "north": {"uv": [4, 10, 12, 16], "texture": "#0"}, - "east": {"uv": [4, 10, 5, 16], "texture": "#0"}, - "south": {"uv": [3.5, 5, 5.5, 6.5], "texture": "#0"}, - "west": {"uv": [11, 10, 12, 16], "texture": "#0"}, - "up": {"uv": [12, 10, 4, 11], "texture": "#0"}, - "down": {"uv": [4, 15, 12, 16], "texture": "#0"} - } - }, { "from": [6, 10, 0], "to": [10, 14, 6], @@ -120,7 +250,7 @@ "east": {"uv": [0, 10.5, 1.5, 11.5], "texture": "#1"}, "south": {"uv": [6, 12, 10, 16], "texture": "#1"}, "west": {"uv": [1.5, 10.5, 3, 11.5], "texture": "#1"}, - "up": {"uv": [10, 10, 6, 16], "texture": "#2"}, + "up": {"uv": [6, 10, 10, 16], "texture": "#2"}, "down": {"uv": [10, 16, 6, 10], "texture": "#2"} } }, @@ -130,7 +260,7 @@ "rotation": {"angle": 0, "axis": "y", "origin": [13, 16, 1]}, "faces": { "north": {"uv": [13, 10, 16, 12], "texture": "#1"}, - "east": {"uv": [0, 10, 16, 12], "texture": "#1"}, + "east": {"uv": [3, 0, 1, 16], "rotation": 90, "texture": "#2"}, "south": {"uv": [0, 10, 3, 12], "texture": "#1"}, "west": {"uv": [0, 10, 16, 12], "texture": "#1"}, "up": {"uv": [0, 0, 3, 16], "texture": "#2"}, @@ -142,7 +272,7 @@ "to": [13, 16, 16], "rotation": {"angle": 0, "axis": "y", "origin": [23, 16, 1]}, "faces": { - "north": {"uv": [3, 10, 13, 12], "texture": "#1"}, + "north": {"uv": [3, 13, 13, 15], "texture": "#2"}, "east": {"uv": [12, 0.5, 12.75, 1], "texture": "#missing"}, "south": {"uv": [3, 10, 13, 12], "texture": "#1"}, "west": {"uv": [0.75, 12, 1.5, 12.5], "texture": "#missing"}, @@ -158,7 +288,7 @@ "north": {"uv": [0, 10, 3, 12], "texture": "#1"}, "east": {"uv": [0, 10, 16, 12], "texture": "#1"}, "south": {"uv": [13, 10, 16, 12], "texture": "#1"}, - "west": {"uv": [0, 10, 16, 12], "texture": "#1"}, + "west": {"uv": [15, 0, 13, 16], "rotation": 270, "texture": "#2"}, "up": {"uv": [13, 0, 16, 16], "texture": "#2"}, "down": {"uv": [0, 10, 16, 12], "texture": "#1"} } @@ -170,141 +300,11 @@ "faces": { "north": {"uv": [3, 10, 13, 12], "texture": "#1"}, "east": {"uv": [12, 1.5, 12.75, 2], "texture": "#1"}, - "south": {"uv": [3, 10, 13, 12], "texture": "#1"}, + "south": {"uv": [3, 3, 13, 1], "texture": "#2"}, "west": {"uv": [4.5, 12, 5.25, 12.5], "texture": "#1"}, - "up": {"uv": [13, 0, 3, 3], "texture": "#2"}, + "up": {"uv": [3, 0, 13, 3], "texture": "#2"}, "down": {"uv": [11.5, 9.5, 9, 10.25], "texture": "#1"} } - }, - { - "from": [16, 11, 4], - "to": [17, 13, 7], - "rotation": {"angle": 0, "axis": "y", "origin": [17, 11, 5]}, - "faces": { - "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "east": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 90, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "texture": "#0"} - } - }, - { - "from": [16, 11, 9], - "to": [17, 13, 12], - "rotation": {"angle": 0, "axis": "y", "origin": [17, 11, 10]}, - "faces": { - "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "east": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 90, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "texture": "#0"} - } - }, - { - "from": [-1, 11, 9], - "to": [0, 13, 12], - "rotation": {"angle": 0, "axis": "y", "origin": [-1, 11, 11]}, - "faces": { - "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "east": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 270, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "rotation": 180, "texture": "#0"} - } - }, - { - "from": [-1, 11, 4], - "to": [0, 13, 7], - "rotation": {"angle": 0, "axis": "y", "origin": [-1, 11, 6]}, - "faces": { - "north": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "east": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "south": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 270, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "rotation": 180, "texture": "#0"} - } - }, - { - "from": [9, 11, 16], - "to": [12, 13, 17], - "rotation": {"angle": 0, "axis": "y", "origin": [11, 11, 17]}, - "faces": { - "north": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "east": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "south": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 180, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "rotation": 270, "texture": "#0"} - } - }, - { - "from": [4, 11, 16], - "to": [7, 13, 17], - "rotation": {"angle": 0, "axis": "y", "origin": [6, 11, 17]}, - "faces": { - "north": {"uv": [0, 0, 0.75, 0.5], "texture": "#0"}, - "east": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "south": {"uv": [0, 0, 3, 2], "texture": "#0"}, - "west": {"uv": [0, 0, 1, 2], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 1], "rotation": 180, "texture": "#0"}, - "down": {"uv": [0, 1, 1, 2], "rotation": 270, "texture": "#0"} - } - }, - { - "from": [13, 16, 14], - "to": [15, 26, 14], - "rotation": {"angle": 0, "axis": "y", "origin": [13, 16, 13]}, - "faces": { - "north": {"uv": [13, 6, 15, 16], "texture": "#0"}, - "east": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, - "south": {"uv": [13, 6, 15, 16], "texture": "#0"}, - "west": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, - "up": {"uv": [0, 0, 0.5, 0], "texture": "#0"}, - "down": {"uv": [0, 0, 0.5, 0], "texture": "#0"} - } - }, - { - "from": [13, 26, 13], - "to": [15, 28, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [13, 22, 15]}, - "faces": { - "north": {"uv": [13, 4, 15, 6], "texture": "#0"}, - "east": {"uv": [13, 4, 15, 6], "texture": "#0"}, - "south": {"uv": [13, 4, 15, 6], "texture": "#0"}, - "west": {"uv": [13, 4, 15, 6], "texture": "#0"}, - "up": {"uv": [13, 2, 15, 4], "texture": "#0"}, - "down": {"uv": [13, 0, 15, 2], "texture": "#0"} - } - }, - { - "from": [14, 16, 13], - "to": [14, 26, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [13, 16, 15]}, - "faces": { - "north": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, - "east": {"uv": [13, 6, 15, 16], "texture": "#0"}, - "south": {"uv": [0, 0, 0, 2.5], "texture": "#0"}, - "west": {"uv": [13, 6, 15, 16], "texture": "#0"}, - "up": {"uv": [0, 0, 0.5, 0], "rotation": 270, "texture": "#0"}, - "down": {"uv": [0, 0, 0.5, 0], "rotation": 90, "texture": "#0"} - } - }, - { - "from": [11, 16, 14], - "to": [12, 24, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [10, 16, 13]}, - "faces": { - "north": {"uv": [13, 8, 14, 16], "texture": "#0"}, - "east": {"uv": [13, 8, 14, 16], "texture": "#0"}, - "south": {"uv": [13, 8, 14, 16], "texture": "#0"}, - "west": {"uv": [13, 8, 14, 16], "texture": "#0"}, - "up": {"uv": [13, 8, 14, 16], "texture": "#0"}, - "down": {"uv": [13, 8, 14, 16], "texture": "#0"} - } } ], "display": { @@ -343,7 +343,13 @@ "name": "drill", "origin": [23, 16, -12], "color": 0, - "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + }, + { + "name": "VoxelShapes", + "origin": [23, 16, -12], + "color": 0, + "children": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] } ] } \ No newline at end of file diff --git a/src/main/resources/assets/carbort/models/item/iron_great_sword.json b/src/main/resources/assets/carbort/models/item/iron_great_sword.json new file mode 100644 index 0000000..ad91464 --- /dev/null +++ b/src/main/resources/assets/carbort/models/item/iron_great_sword.json @@ -0,0 +1,21 @@ +{ + "parent": "minecraft:item/handheld", + "loader": "neoforge:separate_transforms", + "textures": { + "layer0": "carbort:item/iron_great_sword_gui" + }, + "base": { + "parent": "carbort:item/iron_great_sword_handheld" + }, + "perspectives": { + "gui": { + "parent": "carbort:item/iron_great_sword_gui" + }, + "fixed": { + "parent": "carbort:item/iron_great_sword_gui" + }, + "ground": { + "parent": "carbort:item/iron_great_sword_gui" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/carbort/models/item/iron_great_sword_gui.json b/src/main/resources/assets/carbort/models/item/iron_great_sword_gui.json new file mode 100644 index 0000000..8e313e6 --- /dev/null +++ b/src/main/resources/assets/carbort/models/item/iron_great_sword_gui.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "carbort:item/iron_great_sword_gui" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/carbort/models/item/iron_great_sword_handheld.json b/src/main/resources/assets/carbort/models/item/iron_great_sword_handheld.json new file mode 100644 index 0000000..76f7b2a --- /dev/null +++ b/src/main/resources/assets/carbort/models/item/iron_great_sword_handheld.json @@ -0,0 +1,33 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "carbort:item/iron_great_sword" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ 0, -90, 55 ], + "translation": [ 0, 12.0, -1 ], + "scale": [ 2, 2, 0.85 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 4.2, 0.13 ], + "scale": [ 1.5, 1.5, 0.68 ] + }, + "thirdperson_lefthand": { + "rotation": [ 0, 90, -55 ], + "translation": [ 0, 12.0, -1 ], + "scale": [ 2, 2, 0.85 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 90, -25 ], + "translation": [ 1.13, 4.2, 0.13 ], + "scale": [ 1.5, 1.5, 0.68 ] + }, + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 8, 0], + "scale":[ 1.5, 1.5, 1 ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/carbort/textures/block/bedrock_drill.png b/src/main/resources/assets/carbort/textures/block/bedrock_drill.png index 894572a75bcd2bb1b2aca11b1c73b43ce0996dae..36ea307fb47d7cdc123880b58346eb9439ffc474 100644 GIT binary patch delta 379 zcmV->0fhdT1ET|wF@If2L_t(Ijg^zXPQp+a#ea|{4uFY?wzM0Dz(AUiGP1Ba;O69P z;uH7)Jb+K&z=#8J!=1%AK}-k(hS;rt(8R%oPS>H_n_FX~o~5V#?m72C4VlJE8;JqL}fJMY&=d4 ztg5XFI^TyQ*G&!N2h*{Mqx@}rE*2>%l`EoDu87lmL*#8C_B=5J0bl^M+zzH=12f*% zUwaL%YE3o=hwwa2GcX++r`F7Ue5cmjZMe(eKVpEuUnz|tgA4psZUcR046AAr_$xL+ zNF0TnUt9{gNOT@k=aYx~f^K5yFIF|3$o1RSjt zflIeOfKTAi7wD>cm*Qk7NQaivZuw{f6+Tae+ot zmkVj07ivQ4LdW;=+mI-h%2BaYj!w_cqr4V;%ZdgN0cZf%og10Ma`EwRfm_35T{wo9 zQJjG=OzI-Pe_@!kuG&BIoP2{PC?RBM7@ z;{dQ+%$3$vn`y~-6c}zuX O0000e3u;ttkj`1%9($5_ZhyH^m^DO^F0ek!nUbd?Vp)txz6GpHZ7EmylrY_(FlJt+O$BtL%d_L-eT!)kN`m61)lmYFw1g| zRY}{_nk3$F{`>&IrUl2U1YnTB)EeDs13=-_8ci7_s7bt2HY$n}qqVM=69Cr>#EH?G jabozoiO$Q-R-fDfXQ*y&*1%a~00000NkvXXu0mjfv&3&#ti9#E870pv{kwa*pjz`bRcI2{kBl4)e*MSlqZaN;DL^P-hwVG7Q{X+2uc=5Ztxq?B;%N${)DDwxBs^>grD-HC#Dd z;`{5#Zlf&0x0JfEy70cUPp z;L51}zP;Pe`cmRFGBgL9QvlAR(rQ~%qp4sT*^ub@gpc>P)!s!Hq62~11(E81kr$=C r3!?3%l$X$p2V8bxYn}Btx7PUwgGaqrVM&@b00000NkvXXu0mjfg@UQa delta 479 zcmV<50U-W?1BL{UF@L~GL_t(IjdhbhY|}s##(z#N{)lF%R3)*c5)4tiurd^;N<>{6 ziM=BdbZ;i6EM+QtV5b`s2nits3ou0j2EdjTV-eliEtJ+LB!5u|K)cgjDz3_zF*}Ju zL>vGh;sDq4^+gqTJ)e)SpKD*m0am_$84qvu`kbE3*zEQB^LvJf1Fqk=$;LIGv%;d? z>2g+B)YsN&ce+d`A-RyedHIZ$jmuYt7tWs}7m|ysb&WoqgiI$P^|f`rjX!XDGSj~6 z`J_L8aGXnQ)qj>U*YlV3Zua_^QUMyS!>?m!4j|%yTu5D1>9`?n*pE^Rq?&SuqYQQ z-KKAw0rg07A!)b{uIH0PA)nsA(*&jz06R-1x9|AmLReCsauuTql%*1TcW+-al&1_V zbX5l1+TOud?U>9B*QqS1%3GIK>&4dg4ghaoy`b50mcFm~#j{khySI;s1HOJ9^B2+| V0S?VD?Xmy>002ovPDHLkV1jBuPx$MoC0LR9J=Wma%b#FbszOiugV+2$(faxgdnS#bWcMJgyoej$>n~$-<*9A qJb`4>%+tdI#u(&zo|63%0N@kM;)Q!)=+jF80000Px$-bqA3R9J=WmOpFTP!z>aLRXbgN~a9P+Co8It}3(DT}v! z0&96omJkfiP$=E(#f8%M3{9499g3kJ;B+ugNF<7ptJeUcp6pnx@oRvp9x2bv9~IkVJg-CIkSy+iPRFTw*vJ;(4cyU$>uY)vRqGNFtt| zua-@2S^$7=!z;vbywS`n7bv9&0He_;f5ySHi&d9T&v!7nY2n4E?;8j1(YHV;#eTmJ zV@!T6OuIS!;N%Ey1V6sqHJf&&6s@&%9ROB4cL6)RJli;Mwczd};^4kswFe`Z&*w14 zAj`7S%wM+l@%8#6+_0|1Q2V*tP+-tz*ll!(xcgCvzwfA0%dG-0jf zU@)MFl;FjTc!O)LDI#=6TsU24ycrOYeAiWGyup=HC3w-4);c%h1+0{M65u+}INTW^ m={Hyv+64e(O#UPJ-|07#lSD1cer^B&0000Px#%Sl8*R5*>TlCcqkFbqY%a~Xg&7(in%f?P6yS6~y5LF-8Xf?>lhc_ckRlM)$e{Gc%ZZQ@d1P;ihS@EDHc&p66q; z_g=jBV&R;#5Rs&mB!sZOzrwco7dV7)39lwj({z}*swxb_fVOSH%oxY9ympmJM8C-{ zeUft)5fSUb8MC>#n{t5mVfrWC@0*;B&p=~c?MqIi80000OYX|T^*av#kdqSP7UQjlah)K4snW5^76Xq9p8QD+;h&o@ZS|iab@f8?*f-a zZXM7{5JquzdVFLBTM5b{=l0}~i*ujxWZG)OY60Nm^UK=bGk-mXQCwXI9sp^kQBv^q z{KCWiUE}|O30!**dL6(e&2+1RhJ~`oak~zBy&);S33?rr6nKNaF^h(RdUAq8nrUW9 zL2YNJf-s7!(ajYAvt*8vg4J??UT<2%+#;xt=J7pewOssyY@29gkY*aU>u@<7qNKn- z^HEZ?5;WE_o-0f%Z_r0cu{C-A`et0C@eWLBo4|ikKQ#Pi;@es8K>z>%07*qoM6N<$ Ef}_KeeE