Compare commits

...

16 commits

Author SHA1 Message Date
SushiCannibale
9f0e679dd1 fix: loot table + mineable tag
Some checks failed
Build / build (push) Has been cancelled
2025-08-04 18:20:21 +02:00
SushiCannibale
ebc9f61f9b feat: sync with blockentity update packet 2025-08-04 15:15:09 +02:00
SushiCannibale
9188fcaef1 changed my mind: no interface anymore. doesn't fit the style
Some checks are pending
Build / build (push) Waiting to run
2025-08-04 14:40:18 +02:00
SushiCannibale
8be2b08e64 feat: menu sync client server
Some checks are pending
Build / build (push) Waiting to run
2025-08-03 21:11:37 +02:00
SushiCannibale
1ac26e92f7 fix: included 11.1.0 curios version
Some checks are pending
Build / build (push) Waiting to run
2025-08-03 12:08:00 +02:00
SushiCannibale
0d73c80022 feat: floral worbench screen + menu
Some checks are pending
Build / build (push) Waiting to run
2025-08-03 12:07:16 +02:00
SushiCannibale
efb3f565f7 refacto: renaming FloralWorkstation -> FloralWorkbench
Some checks are pending
Build / build (push) Waiting to run
2025-08-02 18:18:07 +02:00
SushiCannibale
f13546e9b4 fix: display floral workbench
Some checks are pending
Build / build (push) Waiting to run
2025-08-02 18:09:57 +02:00
SushiCannibale
5dd5d23221 fix: floral workbench shape 2025-08-02 17:49:23 +02:00
SushiCannibale
85bc6293b1 feat: ignoring datagen output
Some checks are pending
Build / build (push) Waiting to run
2025-08-02 16:26:43 +02:00
SushiCannibale
aa5adbd59e fix: rename + blockstates
Some checks are pending
Build / build (push) Waiting to run
2025-08-02 16:26:24 +02:00
SushiCannibale
b91e4aae21 feat: datagen floral workbench block + flower crown item 2025-08-02 16:25:43 +02:00
SushiCannibale
33e659fa47 fix: workshop -> wokstation + custom model & texture + ao=off
Some checks failed
Build / build (push) Has been cancelled
2025-08-01 00:34:20 +02:00
SushiCannibale
8a5d79280c fix: packedLight forced to 0xff + blank placeholder texture
Some checks are pending
Build / build (push) Waiting to run
2025-07-31 18:22:24 +02:00
SushiCannibale
58d146e04e feat: floral workshop localization + placeholder texture + json files
Some checks failed
Build / build (push) Has been cancelled
2025-07-31 15:49:28 +02:00
SushiCannibale
0776e4657c feat: block + blockentity
Some checks are pending
Build / build (push) Waiting to run
2025-07-31 15:48:20 +02:00
22 changed files with 791 additions and 143 deletions

3
.gitignore vendored
View file

@ -23,4 +23,5 @@ run
runs
run-data
repo
repo
src/generated

View file

@ -1,38 +1,19 @@
package fr.sushi.charmsnfabrics;
import fr.sushi.charmsnfabrics.common.CharmsAndFabricRegistries;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
@Mod(CharmsAndFabrics.MODID)
public class CharmsAndFabrics {
public static final String MODID = "charmsnfabrics";
public CharmsAndFabrics(IEventBus modEventBus, ModContainer modContainer) {
CharmsAndFabricRegistries.register(modEventBus);
CnFRegistries.register(modEventBus);
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}

View file

@ -1,43 +0,0 @@
package fr.sushi.charmsnfabrics.client;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.client.model.FlowerCrownModel;
import fr.sushi.charmsnfabrics.client.renderer.FlowerCrownRenderer;
import fr.sushi.charmsnfabrics.common.CharmsAndFabricRegistries;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.gui.ConfigurationScreen;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
import top.theillusivec4.curios.api.client.ICurioRenderer;
@Mod(value = CharmsAndFabrics.MODID, dist = Dist.CLIENT)
@EventBusSubscriber(modid = CharmsAndFabrics.MODID, value = Dist.CLIENT)
public class CharmsFabricsClient
{
public CharmsFabricsClient(ModContainer container)
{
container.registerExtensionPoint(IConfigScreenFactory.class,
ConfigurationScreen::new);
}
@SubscribeEvent
private static void onClientSetup(final FMLClientSetupEvent event)
{
ICurioRenderer.register(
CharmsAndFabricRegistries.Items.FLOWER_CROWN.get(),
FlowerCrownRenderer::new);
}
@SubscribeEvent
private static void onRegisterLayerDefinitions(
final EntityRenderersEvent.RegisterLayerDefinitions event)
{
event.registerLayerDefinition(CharmsAndFabricsLayers.CROWN_LAYER,
FlowerCrownModel::createLayer);
}
}

View file

@ -0,0 +1,73 @@
package fr.sushi.charmsnfabrics.client;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.client.datagen.CnFBlockLootProvider;
import fr.sushi.charmsnfabrics.client.datagen.CnFBlockTagsProvider;
import fr.sushi.charmsnfabrics.client.datagen.CnFModelProvider;
import fr.sushi.charmsnfabrics.client.model.FlowerCrownModel;
import fr.sushi.charmsnfabrics.client.renderer.FloralWorkbenchRenderer;
import fr.sushi.charmsnfabrics.client.renderer.FlowerCrownRenderer;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.minecraft.data.loot.LootTableProvider;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.gui.ConfigurationScreen;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import top.theillusivec4.curios.api.client.ICurioRenderer;
import java.util.List;
import java.util.Set;
@Mod(value = CharmsAndFabrics.MODID, dist = Dist.CLIENT)
@EventBusSubscriber(modid = CharmsAndFabrics.MODID, value = Dist.CLIENT)
public class CnFClient
{
public CnFClient(ModContainer container)
{
container.registerExtensionPoint(IConfigScreenFactory.class,
ConfigurationScreen::new);
}
@SubscribeEvent
private static void onClientSetup(final FMLClientSetupEvent event)
{
ICurioRenderer.register(CnFRegistries.Items.FLOWER_CROWN.get(),
FlowerCrownRenderer::new);
}
@SubscribeEvent
private static void onRegisterLayerDefinitions(
final EntityRenderersEvent.RegisterLayerDefinitions event)
{
event.registerLayerDefinition(CnFLayers.CROWN_LAYER,
FlowerCrownModel::createLayer);
}
@SubscribeEvent
private static void onRegisterRenderers(
final EntityRenderersEvent.RegisterRenderers event)
{
event.registerBlockEntityRenderer(
CnFRegistries.Entities.FLORAL_WORKBENCH_BLOCKENTITY.get(),
FloralWorkbenchRenderer::new);
}
@SubscribeEvent
private static void onGatherClientData(final GatherDataEvent.Client event)
{
event.createProvider(CnFModelProvider::new);
event.createProvider(
(output, lookup) -> new LootTableProvider(output, Set.of(),
List.of(new LootTableProvider.SubProviderEntry(
CnFBlockLootProvider::new,
LootContextParamSets.BLOCK)), lookup));
event.createProvider(CnFBlockTagsProvider::new);
}
}

View file

@ -4,7 +4,7 @@ import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.resources.ResourceLocation;
public class CharmsAndFabricsLayers
public class CnFLayers
{
public static final ModelLayerLocation CROWN_LAYER = new ModelLayerLocation(
ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,

View file

@ -0,0 +1,31 @@
package fr.sushi.charmsnfabrics.client.datagen;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.loot.BlockLootSubProvider;
import net.minecraft.world.flag.FeatureFlags;
import net.minecraft.world.level.block.Block;
import java.util.Set;
public class CnFBlockLootProvider extends BlockLootSubProvider
{
public CnFBlockLootProvider(HolderLookup.Provider registries)
{
super(Set.of(), FeatureFlags.DEFAULT_FLAGS, registries);
}
@Override
protected Iterable<Block> getKnownBlocks()
{
return CnFRegistries.Blocks.BLOCKS.getEntries().stream()
.map(block -> (Block) block.get())
.toList();
}
@Override
protected void generate()
{
this.dropSelf(CnFRegistries.Blocks.FLORAL_WORKBENCH.get());
}
}

View file

@ -0,0 +1,25 @@
package fr.sushi.charmsnfabrics.client.datagen;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.tags.BlockTags;
import net.neoforged.neoforge.common.data.BlockTagsProvider;
import java.util.concurrent.CompletableFuture;
public class CnFBlockTagsProvider extends BlockTagsProvider
{
public CnFBlockTagsProvider(PackOutput output,
CompletableFuture<HolderLookup.Provider> lookupProvider)
{
super(output, lookupProvider, CharmsAndFabrics.MODID);
}
@Override
protected void addTags(HolderLookup.Provider provider)
{
this.tag(BlockTags.MINEABLE_WITH_AXE).add(CnFRegistries.Blocks.FLORAL_WORKBENCH.get());
}
}

View file

@ -0,0 +1,49 @@
package fr.sushi.charmsnfabrics.client.datagen;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.minecraft.client.data.models.BlockModelGenerators;
import net.minecraft.client.data.models.ItemModelGenerators;
import net.minecraft.client.data.models.ModelProvider;
import net.minecraft.client.data.models.MultiVariant;
import net.minecraft.client.data.models.model.ModelLocationUtils;
import net.minecraft.client.data.models.model.ModelTemplates;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
public class CnFModelProvider extends ModelProvider
{
public CnFModelProvider(PackOutput output)
{
super(output, CharmsAndFabrics.MODID);
}
private void registerFloralWorkbench(BlockModelGenerators blockModels)
{
Block block = CnFRegistries.Blocks.FLORAL_WORKBENCH.get();
ResourceLocation model = ModelLocationUtils.getModelLocation(block);
MultiVariant variants = BlockModelGenerators.plainVariant(model);
blockModels.blockStateOutput.accept(
BlockModelGenerators.createSimpleBlock(block, variants)
.with(BlockModelGenerators.ROTATION_HORIZONTAL_FACING_ALT));
// blockModels.modelOutput.accept(ModelLocationUtils.getModelLocation(block));
}
private void registerFlowerCrown(ItemModelGenerators itemModels)
{
Item item = CnFRegistries.Items.FLOWER_CROWN.get();
itemModels.generateFlatItem(item, ModelTemplates.FLAT_ITEM);
}
@Override
protected void registerModels(BlockModelGenerators blockModels,
ItemModelGenerators itemModels)
{
this.registerFlowerCrown(itemModels);
this.registerFloralWorkbench(blockModels);
}
}

View file

@ -0,0 +1,49 @@
package fr.sushi.charmsnfabrics.client.renderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.client.CnFLayers;
import fr.sushi.charmsnfabrics.client.model.FlowerCrownModel;
import fr.sushi.charmsnfabrics.common.entities.block.FloralWorkbenchBlockEntity;
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.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
public class FloralWorkbenchRenderer implements BlockEntityRenderer<FloralWorkbenchBlockEntity>
{
private final FlowerCrownModel model;
public FloralWorkbenchRenderer(BlockEntityRendererProvider.Context ctx)
{
this.model = new FlowerCrownModel(ctx.bakeLayer(CnFLayers.CROWN_LAYER));
}
@Override
public void render(FloralWorkbenchBlockEntity blockEntity,
float partialTick, PoseStack poseStack,
MultiBufferSource bufferSource, int packedLight, int packedOverlay,
Vec3 cameraPos)
{
if (!blockEntity.hasCrown()) {
return;
}
poseStack.pushPose();
float yRot =
blockEntity.getRandomSource().nextFloat() * (float) Math.PI * partialTick;
poseStack.translate(0.5f, 1.625f, 0.5f);
// poseStack.rotateAround(Axis.YP.rotationDegrees(yRot), 0.0f, 0.0f, 0.0f);
ResourceLocation texture =
ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,
"textures/models/accessory/flower_crown.png");
VertexConsumer consumer =
bufferSource.getBuffer(RenderType.entityCutout(texture));
this.model.renderToBuffer(poseStack, consumer, packedLight, packedOverlay);
poseStack.popPose();
}
}

View file

@ -2,7 +2,7 @@ package fr.sushi.charmsnfabrics.client.renderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import fr.sushi.charmsnfabrics.client.CharmsAndFabricsLayers;
import fr.sushi.charmsnfabrics.client.CnFLayers;
import fr.sushi.charmsnfabrics.client.model.FlowerCrownModel;
import fr.sushi.charmsnfabrics.common.item.FlowerCrown;
import net.minecraft.client.Minecraft;
@ -28,7 +28,7 @@ public class FlowerCrownRenderer implements ICurioRenderer
{
this.model = new FlowerCrownModel(
Minecraft.getInstance().getEntityModels()
.bakeLayer(CharmsAndFabricsLayers.CROWN_LAYER));
.bakeLayer(CnFLayers.CROWN_LAYER));
}
@Override
@ -43,11 +43,9 @@ public class FlowerCrownRenderer implements ICurioRenderer
ResourceLocation texture = item.getModelTexture();
VertexConsumer vertexconsumer =
ItemRenderer.getArmorFoilBuffer(renderTypeBuffer,
RenderType.entityCutout(
texture),
stack.hasFoil());
RenderType.entityCutout(texture), stack.hasFoil());
ICurioRenderer.setupHumanoidAnimations(this.model, renderState);
this.model.renderToBuffer(poseStack, vertexconsumer, packedLight,
OverlayTexture.NO_OVERLAY);
OverlayTexture.NO_OVERLAY);
}
}

View file

@ -1,56 +0,0 @@
package fr.sushi.charmsnfabrics.common;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.common.item.FlowerCrown;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
public class CharmsAndFabricRegistries
{
public static class Items
{
public static final DeferredRegister.Items ITEMS =
DeferredRegister.createItems(CharmsAndFabrics.MODID);
public static final DeferredItem<Item> FLOWER_CROWN =
ITEMS.registerItem("flower_crown",
(properties) -> new FlowerCrown(
properties.stacksTo(1)));
}
public static class Tabs
{
public static final DeferredRegister<CreativeModeTab>
CREATIVE_MODE_TABS =
DeferredRegister.create(Registries.CREATIVE_MODE_TAB,
CharmsAndFabrics.MODID);
public static final DeferredHolder<CreativeModeTab, CreativeModeTab>
EXAMPLE_TAB = CREATIVE_MODE_TABS.register("charmsnfabrics_tab",
() -> CreativeModeTab
.builder()
.title(Component.translatable(
"itemGroup.charmsnfabrics"))
.withTabsBefore(
CreativeModeTabs.COMBAT)
.icon(Items.FLOWER_CROWN.get()::getDefaultInstance)
.displayItems(
(parameters, output) ->
{
output.accept(
Items.FLOWER_CROWN.get());
})
.build());
}
public static void register(IEventBus bus)
{
Items.ITEMS.register(bus);
Tabs.CREATIVE_MODE_TABS.register(bus);
}
}

View file

@ -0,0 +1,110 @@
package fr.sushi.charmsnfabrics.common;
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
import fr.sushi.charmsnfabrics.common.block.FloralWorkbench;
import fr.sushi.charmsnfabrics.common.entities.block.FloralWorkbenchBlockEntity;
import fr.sushi.charmsnfabrics.common.item.FlowerCrown;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.Set;
import java.util.function.Supplier;
public class CnFRegistries
{
public static class Items
{
public static final DeferredRegister.Items ITEMS =
DeferredRegister.createItems(CharmsAndFabrics.MODID);
public static final DeferredItem<Item> FLOWER_CROWN =
ITEMS.registerItem("flower_crown",
(properties) -> new FlowerCrown(
properties.stacksTo(1)));
/* BlockItems */
public static final DeferredItem<BlockItem> FLORAL_WORKBENCH =
ITEMS.registerItem("floral_workbench",
properties -> new BlockItem(
Blocks.FLORAL_WORKBENCH.get(), properties));
}
public static class Blocks
{
public static final DeferredRegister.Blocks BLOCKS =
DeferredRegister.createBlocks(CharmsAndFabrics.MODID);
public static final DeferredBlock<Block> FLORAL_WORKBENCH =
BLOCKS.register("floral_workbench",
registry_name -> new FloralWorkbench(
BlockBehaviour.Properties.of()
.setId(ResourceKey.create(
Registries.BLOCK,
registry_name))
.noOcclusion()
.mapColor(
MapColor.WOOD)
.strength(2.0f, 3.0f)
.sound(SoundType.WOOD)
.ignitedByLava()));
}
public static class Tabs
{
public static final DeferredRegister<CreativeModeTab>
CREATIVE_MODE_TABS =
DeferredRegister.create(Registries.CREATIVE_MODE_TAB,
CharmsAndFabrics.MODID);
public static final DeferredHolder<CreativeModeTab, CreativeModeTab>
CHARMS_AND_FABRICS_TAB =
CREATIVE_MODE_TABS.register("charmsnfabrics_tab",
() -> CreativeModeTab.builder()
.title(Component.translatable(
"itemGroup.charmsnfabrics"))
.withTabsBefore(
CreativeModeTabs.COMBAT)
.icon(Items.FLOWER_CROWN.get()::getDefaultInstance)
.displayItems(
(parameters, output) ->
{
output.accept(
Items.FLOWER_CROWN.get());
output.accept(
Blocks.FLORAL_WORKBENCH.toStack());
}).build());
}
public static class Entities
{
public static final DeferredRegister<BlockEntityType<?>>
BLOCK_ENTITY_TYPES =
DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE,
CharmsAndFabrics.MODID);
public static final Supplier<BlockEntityType<FloralWorkbenchBlockEntity>>
FLORAL_WORKBENCH_BLOCKENTITY =
BLOCK_ENTITY_TYPES.register("floral_workbench_entity",
() -> new BlockEntityType<>(
FloralWorkbenchBlockEntity::new,
Set.of(Blocks.FLORAL_WORKBENCH.get())));
}
public static void register(IEventBus bus)
{
Items.ITEMS.register(bus);
Blocks.BLOCKS.register(bus);
Tabs.CREATIVE_MODE_TABS.register(bus);
Entities.BLOCK_ENTITY_TYPES.register(bus);
}
}

View file

@ -0,0 +1,154 @@
package fr.sushi.charmsnfabrics.common.block;
import com.mojang.serialization.MapCodec;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import fr.sushi.charmsnfabrics.common.entities.block.FloralWorkbenchBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.*;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
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.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.neoforge.items.IItemHandler;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class FloralWorkbench extends BaseEntityBlock
{
public static final MapCodec<FloralWorkbench> CODEC =
simpleCodec(FloralWorkbench::new);
public static final EnumProperty<Direction> FACING =
HorizontalDirectionalBlock.FACING;
private static final VoxelShape LEGS =
Shapes.or(Block.box(1.0, 0.0, 1.0, 3.0, 12.0, 3.0),
Block.box(1.0, 0.0, 13.0, 3.0, 12.0, 15.0),
Block.box(13.0, 0.0, 13.0, 15.0, 12.0, 15.0),
Block.box(13.0, 0.0, 1.0, 15.0, 12.0, 3.0));
private static final VoxelShape TABLE = Block.column(16.0, 12.0, 14.0);
private static final VoxelShape SUPPORT = Block.column(12.0, 2.0, 3.0);
private static final Map<Direction.Axis, VoxelShape> SHAPES =
Shapes.rotateHorizontalAxis(Shapes.or(LEGS, TABLE, SUPPORT));
public FloralWorkbench(BlockBehaviour.Properties properties)
{
super(properties);
this.registerDefaultState(
this.stateDefinition.any().setValue(FACING, Direction.NORTH));
}
@Override
protected MapCodec<? extends BaseEntityBlock> codec()
{
return CODEC;
}
@Override
protected void createBlockStateDefinition(
StateDefinition.Builder<Block, BlockState> builder)
{
builder.add(FACING);
}
@Override
public @Nullable BlockState getStateForPlacement(BlockPlaceContext ctx)
{
return this.defaultBlockState().setValue(FACING,
ctx.getHorizontalDirection().getClockWise());
}
@Override
protected BlockState rotate(BlockState state, Rotation rot)
{
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level,
BlockPos pos, CollisionContext context)
{
return SHAPES.get(state.getValue(FACING).getAxis());
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state)
{
return new FloralWorkbenchBlockEntity(pos, state);
}
@Override
protected InteractionResult useItemOn(ItemStack stack, BlockState state,
Level level, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult hitResult)
{
if (level.getBlockEntity(
pos) instanceof FloralWorkbenchBlockEntity blockentity)
{
boolean hasCrown = blockentity.hasCrown();
boolean emptyHand = stack.isEmpty();
if (!level.isClientSide())
{
IItemHandler handler = blockentity.getItemHandler();
if (hasCrown && emptyHand)
{
ItemStack extracted = handler.extractItem(0, 1, false);
if (!player.hasInfiniteMaterials())
{
Containers.dropItemStack(level, pos.getX(),
pos.getY() + 1.0f, pos.getZ(), extracted);
}
blockentity.setChanged();
level.sendBlockUpdated(pos, state, state, 3);
return InteractionResult.SUCCESS_SERVER;
}
else if (stack.is(CnFRegistries.Items.FLOWER_CROWN.get()) &&
!hasCrown)
{
handler.insertItem(0, stack.copy(), false);
stack.consume(1, player);
blockentity.setChanged();
level.sendBlockUpdated(pos, state, state, 3);
return InteractionResult.CONSUME;
}
else
{
return InteractionResult.PASS;
}
}
else
{
return !hasCrown ^ emptyHand ? InteractionResult.SUCCESS :
InteractionResult.PASS;
}
}
else
{
return InteractionResult.PASS;
}
}
@Override
protected @Nullable MenuProvider getMenuProvider(BlockState state,
Level level, BlockPos pos)
{
return null;
}
}

View file

@ -0,0 +1,86 @@
package fr.sushi.charmsnfabrics.common.entities.block;
import fr.sushi.charmsnfabrics.common.CnFRegistries;
import net.minecraft.core.BlockPos;
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.util.RandomSource;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.Nullable;
public class FloralWorkbenchBlockEntity extends BlockEntity
{
private final RandomSource randomSource = RandomSource.create();
private final ItemStackHandler itemHandler = new ItemStackHandler(1);
public FloralWorkbenchBlockEntity(BlockPos pos, BlockState blockState)
{
super(CnFRegistries.Entities.FLORAL_WORKBENCH_BLOCKENTITY.get(), pos,
blockState);
}
@Override
protected void saveAdditional(CompoundTag nbt,
HolderLookup.Provider levelRegistry)
{
super.saveAdditional(nbt, levelRegistry);
CompoundTag tag = itemHandler.serializeNBT(levelRegistry);
nbt.put("Inventory", tag);
}
@Override
protected void loadAdditional(CompoundTag nbt,
HolderLookup.Provider levelRegistry)
{
super.loadAdditional(nbt, levelRegistry);
nbt.getCompound("Inventory")
.ifPresent(tag -> itemHandler.deserializeNBT(levelRegistry, tag));
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries)
{
CompoundTag tag = super.getUpdateTag(registries);
tag.put("Inventory", itemHandler.serializeNBT(registries));
return tag;
}
@Override
public void handleUpdateTag(CompoundTag nbt,
HolderLookup.Provider lookupProvider)
{
super.handleUpdateTag(nbt, lookupProvider);
nbt.getCompound("Inventory")
.ifPresent(tag -> itemHandler.deserializeNBT(lookupProvider, tag));
}
@Override
public @Nullable Packet<ClientGamePacketListener> getUpdatePacket()
{
return ClientboundBlockEntityDataPacket.create(this);
}
public RandomSource getRandomSource()
{
return this.randomSource;
}
public boolean hasCrown()
{
return this.itemHandler.getStackInSlot(0)
.is(CnFRegistries.Items.FLOWER_CROWN.get());
}
public IItemHandler getItemHandler()
{
return this.itemHandler;
}
}

View file

@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "charmsnfabrics:item/flower_crown"
}
}

View file

@ -1,6 +1,7 @@
{
"itemGroup.charmsnfabrics": "Charms & Fabrics",
"item.charmsnfabrics.flower_crown": "Flower Crown",
"item.charmsnfabrics.floral_workbench": "Floral Workbench",
"charmsnfabrics.configuration.title": "Charms & Fabrics Configs",
"charmsnfabrics.configuration.section.charmsnfabrics.common.toml": "Charms & Fabrics Configs",

View file

@ -0,0 +1,201 @@
{
"format_version": "1.21.6",
"credit": "Made with Blockbench",
"texture_size": [64, 64],
"render_type": "minecraft:cutout_mipped",
"textures": {
"0": "charmsnfabrics:block/floral_workbench",
"particle": "minecraft:block/oak_planks"
},
"elements": [
{
"from": [1, 0, 1],
"to": [3, 12, 3],
"faces": {
"north": {"uv": [0.5, 12.5, 1, 15.5], "texture": "#0"},
"east": {"uv": [0, 12.5, 0.5, 15.5], "texture": "#0"},
"south": {"uv": [1.5, 12.5, 2, 15.5], "texture": "#0"},
"west": {"uv": [1, 12.5, 1.5, 15.5], "texture": "#0"},
"up": {"uv": [1, 12.5, 0.5, 12], "texture": "#0"},
"down": {"uv": [1.5, 12, 1, 12.5], "texture": "#0"}
}
},
{
"from": [1, 0, 13],
"to": [3, 12, 15],
"faces": {
"north": {"uv": [0.5, 12.5, 1, 15.5], "texture": "#0"},
"east": {"uv": [0, 12.5, 0.5, 15.5], "texture": "#0"},
"south": {"uv": [1.5, 12.5, 2, 15.5], "texture": "#0"},
"west": {"uv": [1, 12.5, 1.5, 15.5], "texture": "#0"},
"up": {"uv": [1, 12.5, 0.5, 12], "texture": "#0"},
"down": {"uv": [1.5, 12, 1, 12.5], "texture": "#0"}
}
},
{
"from": [13, 0, 13],
"to": [15, 12, 15],
"faces": {
"north": {"uv": [0.5, 12.5, 1, 15.5], "texture": "#0"},
"east": {"uv": [0, 12.5, 0.5, 15.5], "texture": "#0"},
"south": {"uv": [1.5, 12.5, 2, 15.5], "texture": "#0"},
"west": {"uv": [1, 12.5, 1.5, 15.5], "texture": "#0"},
"up": {"uv": [1, 12.5, 0.5, 12], "texture": "#0"},
"down": {"uv": [1.5, 12, 1, 12.5], "texture": "#0"}
}
},
{
"from": [13, 0, 1],
"to": [15, 12, 3],
"faces": {
"north": {"uv": [0.5, 12.5, 1, 15.5], "texture": "#0"},
"east": {"uv": [0, 12.5, 0.5, 15.5], "texture": "#0"},
"south": {"uv": [1.5, 12.5, 2, 15.5], "texture": "#0"},
"west": {"uv": [1, 12.5, 1.5, 15.5], "texture": "#0"},
"up": {"uv": [1, 12.5, 0.5, 12], "texture": "#0"},
"down": {"uv": [1.5, 12, 1, 12.5], "texture": "#0"}
}
},
{
"from": [0, 12, 0],
"to": [16, 14, 16],
"faces": {
"north": {"uv": [4, 15.5, 8, 16], "texture": "#0"},
"east": {"uv": [0, 15.5, 4, 16], "texture": "#0"},
"south": {"uv": [12, 15.5, 16, 16], "texture": "#0"},
"west": {"uv": [8, 15.5, 12, 16], "texture": "#0"},
"up": {"uv": [8, 15.5, 4, 11.5], "texture": "#0"},
"down": {"uv": [12, 11.5, 8, 15.5], "texture": "#0"}
}
},
{
"from": [2, 2, 2],
"to": [14, 3, 14],
"faces": {
"north": {"uv": [3, 11.25, 6, 11.5], "texture": "#0"},
"east": {"uv": [0, 11.25, 3, 11.5], "texture": "#0"},
"south": {"uv": [9, 11.25, 12, 11.5], "texture": "#0"},
"west": {"uv": [6, 11.25, 9, 11.5], "texture": "#0"},
"up": {"uv": [6, 11.25, 3, 8.25], "texture": "#0"},
"down": {"uv": [9, 8.25, 6, 11.25], "texture": "#0"}
}
},
{
"from": [3, 14, 3],
"to": [13, 15, 13],
"faces": {
"north": {"uv": [2.5, 8, 5, 8.25], "texture": "#0"},
"east": {"uv": [0, 8, 2.5, 8.25], "texture": "#0"},
"south": {"uv": [7.5, 8, 10, 8.25], "texture": "#0"},
"west": {"uv": [5, 8, 7.5, 8.25], "texture": "#0"},
"up": {"uv": [5, 8, 2.5, 5.5], "texture": "#0"},
"down": {"uv": [7.5, 5.5, 5, 8], "texture": "#0"}
}
},
{
"from": [0, 14.25, 0],
"to": [16, 14.25, 16],
"faces": {
"north": {"uv": [7.5, 8, 11.5, 8], "texture": "#0"},
"east": {"uv": [3.5, 8, 7.5, 8], "texture": "#0"},
"south": {"uv": [15.5, 8, 19.5, 8], "texture": "#0"},
"west": {"uv": [11.5, 8, 15.5, 8], "texture": "#0"},
"up": {"uv": [11.5, 8, 7.5, 4], "texture": "#0"},
"down": {"uv": [15.5, 4, 11.5, 8], "texture": "#0"}
}
},
{
"from": [0, 0, -0.25],
"to": [8, 14, -0.25],
"faces": {
"north": {"uv": [12, 8, 14, 11.5], "texture": "#0"},
"east": {"uv": [12, 8, 12, 11.5], "texture": "#0"},
"south": {"uv": [14, 8, 16, 11.5], "texture": "#0"},
"west": {"uv": [14, 8, 14, 11.5], "texture": "#0"},
"up": {"uv": [14, 8, 12, 8], "texture": "#0"},
"down": {"uv": [16, 8, 14, 8], "texture": "#0"}
}
},
{
"from": [8, 0, 16.25],
"to": [16, 14, 16.25],
"faces": {
"north": {"uv": [12, 11.5, 14, 15], "texture": "#0"},
"east": {"uv": [12, 11.5, 12, 15], "texture": "#0"},
"south": {"uv": [14, 11.5, 16, 15], "texture": "#0"},
"west": {"uv": [14, 11.5, 14, 15], "texture": "#0"},
"up": {"uv": [14, 11.5, 12, 11.5], "texture": "#0"},
"down": {"uv": [16, 11.5, 14, 11.5], "texture": "#0"}
}
},
{
"from": [4, 3, 3],
"to": [9, 5, 8],
"faces": {
"north": {"uv": [1.75, 3.5, 3, 4], "texture": "#0"},
"east": {"uv": [0.5, 3.5, 1.75, 4], "texture": "#0"},
"south": {"uv": [4.25, 3.5, 5.5, 4], "texture": "#0"},
"west": {"uv": [3, 3.5, 4.25, 4], "texture": "#0"},
"up": {"uv": [3, 3.5, 1.75, 2.25], "texture": "#0"},
"down": {"uv": [4.25, 2.25, 3, 3.5], "texture": "#0"}
}
},
{
"from": [4, 3, 9],
"to": [12, 5, 13],
"faces": {
"north": {"uv": [1, 5, 3, 5.5], "texture": "#0"},
"east": {"uv": [0, 5, 1, 5.5], "texture": "#0"},
"south": {"uv": [4, 5, 6, 5.5], "texture": "#0"},
"west": {"uv": [3, 5, 4, 5.5], "texture": "#0"},
"up": {"uv": [3, 5, 1, 4], "texture": "#0"},
"down": {"uv": [5, 4, 3, 5], "texture": "#0"}
}
}
],
"display": {
"thirdperson_righthand": {
"scale": [0.5, 0.5, 0.5]
},
"thirdperson_lefthand": {
"scale": [0.5, 0.5, 0.5]
},
"firstperson_righthand": {
"scale": [0.5, 0.5, 0.5]
},
"firstperson_lefthand": {
"scale": [0.5, 0.5, 0.5]
},
"ground": {
"translation": [0, 2, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 45, 0],
"scale": [0.625, 0.625, 0.625]
},
"head": {
"translation": [0, 1, 0]
}
},
"groups": [
{
"name": "legs",
"origin": [8, 8, 8],
"color": 0,
"children": [0, 1, 2, 3]
},
{
"name": "station",
"origin": [8, 8, 8],
"color": 0,
"children": [4, 5, 6]
},
{
"name": "decoration",
"origin": [8, 8, 8],
"color": 0,
"children": [7, 8, 9, 10, 11]
}
]
}

View file

@ -1,6 +0,0 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "charmsnfabrics:item/flower_crown"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

After

Width:  |  Height:  |  Size: 362 B

Before After
Before After

View file

@ -89,7 +89,7 @@ description='''${mod_description}'''
[[dependencies.${mod_id}]]
modId="curios"
type="required"
versionRange="[11.0.1,)"
versionRange="[11.0.1,]"
ordering="BEFORE"
side="BOTH"