feat: dynamic flower crown model + other thingsss
Some checks are pending
Build / build (push) Waiting to run
|
@ -4,11 +4,13 @@ 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.FlowerCrownItemModel;
|
||||
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.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
|
@ -17,6 +19,7 @@ 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.event.RegisterItemModelsEvent;
|
||||
import net.neoforged.neoforge.client.gui.ConfigurationScreen;
|
||||
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
||||
import net.neoforged.neoforge.data.event.GatherDataEvent;
|
||||
|
@ -39,7 +42,8 @@ public class CnFClient
|
|||
private static void onClientSetup(final FMLClientSetupEvent event)
|
||||
{
|
||||
ICurioRenderer.register(CnFRegistries.Items.FLOWER_CROWN.get(),
|
||||
FlowerCrownRenderer::new);
|
||||
() -> new FlowerCrownRenderer(
|
||||
FlowerCrownRenderer.createModel()));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -70,4 +74,22 @@ public class CnFClient
|
|||
LootContextParamSets.BLOCK)), lookup));
|
||||
event.createProvider(CnFBlockTagsProvider::new);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
private static void onRegisterItemModels(final RegisterItemModelsEvent event)
|
||||
{
|
||||
event.register(
|
||||
ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,
|
||||
"flower_crown_loader"),
|
||||
FlowerCrownItemModel.Unbaked.MAP_CODEC);
|
||||
}
|
||||
|
||||
// @SubscribeEvent
|
||||
// private static void onRegisterStandaloneModels(
|
||||
// ModelEvent.RegisterStandalone event)
|
||||
// {
|
||||
// event.register(new StandaloneModelKey<>(
|
||||
// ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,
|
||||
// "item/flower")), StandaloneModelBaker.quadCollection());
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -5,19 +5,20 @@ import com.mojang.serialization.MapCodec;
|
|||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.BlockElement;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||
import net.minecraft.client.renderer.block.model.TextureSlots;
|
||||
import net.minecraft.client.renderer.item.*;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.client.ClientHooks;
|
||||
import net.neoforged.neoforge.client.NeoForgeRenderTypes;
|
||||
import net.neoforged.neoforge.client.RenderTypeGroup;
|
||||
import net.neoforged.neoforge.client.model.ComposedModelState;
|
||||
import net.neoforged.neoforge.client.model.UnbakedElementsHelper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -29,70 +30,76 @@ import java.util.List;
|
|||
|
||||
public class FlowerCrownItemModel implements ItemModel
|
||||
{
|
||||
/* TODO: Center flower0&1 textures and play with transform to get them at the right place for every layer */
|
||||
private static final Transformation TRANSFORM =
|
||||
new Transformation(new Vector3f(), new Quaternionf(),
|
||||
new Vector3f(1.0f, 1.0f, 1.004f), new Quaternionf());
|
||||
private static final ModelDebugName DEBUG_NAME =
|
||||
() -> "FlowerCrownItemModel";
|
||||
|
||||
// private final FlowerCrownItemModel.Unbaked unbakedModel;
|
||||
// private final ItemTransforms transforms;
|
||||
private final ItemModel bakedBase;
|
||||
private final BakingContext bakingContext;
|
||||
private final ItemTransforms baseTransform;
|
||||
private final Unbaked rawModel;
|
||||
private final BakingContext context;
|
||||
private ModelRenderProperties renderProperties;
|
||||
|
||||
public FlowerCrownItemModel(ItemModel bakedBase, BakingContext context)
|
||||
public FlowerCrownItemModel(Unbaked rawModel, BakingContext context)
|
||||
{
|
||||
this.bakedBase = bakedBase;
|
||||
this.bakingContext = context;
|
||||
ResolvedModel baseItemModel = bakingContext.blockModelBaker().getModel(
|
||||
ResourceLocation.withDefaultNamespace("item/generated"));
|
||||
this.baseTransform = baseItemModel.getTopTransforms();
|
||||
this.rawModel = rawModel;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private ResourceLocation getFlowerLocation(int layer)
|
||||
{
|
||||
return ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,
|
||||
"flowers/flower" + layer);
|
||||
"flower/flower" + layer);
|
||||
}
|
||||
|
||||
/* Prevent Z fighting */
|
||||
private Transformation getLayerTransform(int layer)
|
||||
private static RenderTypeGroup getLayerRenderTypes(boolean unlit)
|
||||
{
|
||||
return new Transformation(new Vector3f(), new Quaternionf(),
|
||||
new Vector3f(0.0f, 0.0f, 1.0f + (layer / 100f)),
|
||||
new Quaternionf());
|
||||
return new RenderTypeGroup(RenderType.translucent(), unlit ?
|
||||
NeoForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get() :
|
||||
NeoForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get());
|
||||
}
|
||||
|
||||
public ItemModel bakeForColors(List<DyeColor> colors)
|
||||
/**
|
||||
* Bakes the base and updates the LayerRenderState quads
|
||||
*/
|
||||
private ItemModel bakeBase()
|
||||
{
|
||||
ModelState state = BlockModelRotation.X0_Y0;
|
||||
SpriteGetter sprites = this.bakingContext.blockModelBaker().sprites();
|
||||
ModelBaker baker = this.context.blockModelBaker();
|
||||
ResolvedModel resolvedModel = baker.getModel(this.rawModel.base);
|
||||
TextureSlots slots = resolvedModel.getTopTextureSlots();
|
||||
|
||||
List<ItemModel> submodels = new ArrayList<>();
|
||||
submodels.add(this.bakedBase);
|
||||
List<BakedQuad> quads = resolvedModel
|
||||
.bakeTopGeometry(slots, baker, BlockModelRotation.X0_Y0)
|
||||
.getAll();
|
||||
this.renderProperties =
|
||||
ModelRenderProperties.fromResolvedModel(baker, resolvedModel,
|
||||
slots);
|
||||
return new BlockModelWrapper(List.of(), quads, this.renderProperties);
|
||||
}
|
||||
|
||||
for (int layer = 0; layer < colors.size(); layer++)
|
||||
{
|
||||
ResourceLocation texture = this.getFlowerLocation(layer);
|
||||
Material material = ClientHooks.getBlockMaterial(texture);
|
||||
TextureAtlasSprite sprite = sprites.get(material, DEBUG_NAME);
|
||||
private ItemModel bakeLayer(int layer)
|
||||
{
|
||||
SpriteGetter sprites = this.context.blockModelBaker().sprites();
|
||||
Material material =
|
||||
ClientHooks.getBlockMaterial(this.getFlowerLocation(layer));
|
||||
TextureAtlasSprite sprite = sprites.get(material, DEBUG_NAME);
|
||||
/* Create all the bits that makes the model */
|
||||
List<BlockElement> bits =
|
||||
UnbakedElementsHelper.createUnbakedItemElements(0, sprite);
|
||||
List<BakedQuad> quads =
|
||||
UnbakedElementsHelper.bakeElements(bits, $ -> sprite,
|
||||
new ComposedModelState(BlockModelRotation.X0_Y0,
|
||||
TRANSFORM));
|
||||
return new BlockModelWrapper(List.of(), quads, this.renderProperties);
|
||||
}
|
||||
|
||||
/* ***** TODO: Multiply pixels with dye color **** */
|
||||
|
||||
List<BlockElement> unbaked =
|
||||
UnbakedElementsHelper.createUnbakedItemElements(0, sprite);
|
||||
List<BakedQuad> quads =
|
||||
UnbakedElementsHelper.bakeElements(unbaked, mat -> sprite,
|
||||
new ComposedModelState(state,
|
||||
this.getLayerTransform(layer)));
|
||||
|
||||
ModelRenderProperties renderProperties =
|
||||
new ModelRenderProperties(false, sprite,
|
||||
this.baseTransform);
|
||||
submodels.add(
|
||||
new BlockModelWrapper(List.of(), quads, renderProperties));
|
||||
}
|
||||
|
||||
/* ****************************************************************** */
|
||||
return new CompositeModel(submodels);
|
||||
private CompositeModel composeModel()
|
||||
{
|
||||
List<ItemModel> models = new ArrayList<>();
|
||||
models.add(this.bakeBase());
|
||||
models.add(this.bakeLayer(0));
|
||||
return new CompositeModel(models);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,18 +108,18 @@ public class FlowerCrownItemModel implements ItemModel
|
|||
ItemDisplayContext displayContext, @Nullable ClientLevel level,
|
||||
@Nullable LivingEntity entity, int seed)
|
||||
{
|
||||
ItemStackRenderState.LayerRenderState freshLayer =
|
||||
renderState.newLayer();
|
||||
this.composeModel()
|
||||
.update(renderState, stack, itemModelResolver, displayContext,
|
||||
level, entity, seed);
|
||||
}
|
||||
|
||||
public record Unbaked(
|
||||
ResourceLocation baseModel) implements ItemModel.Unbaked
|
||||
public record Unbaked(ResourceLocation base) implements ItemModel.Unbaked
|
||||
{
|
||||
|
||||
public static final MapCodec<FlowerCrownItemModel.Unbaked> MAP_CODEC =
|
||||
RecordCodecBuilder.mapCodec(unbaked -> unbaked
|
||||
.group(ResourceLocation.CODEC.fieldOf("base").forGetter(
|
||||
FlowerCrownItemModel.Unbaked::baseModel))
|
||||
FlowerCrownItemModel.Unbaked::base))
|
||||
.apply(unbaked, FlowerCrownItemModel.Unbaked::new));
|
||||
|
||||
@Override
|
||||
|
@ -124,32 +131,13 @@ public class FlowerCrownItemModel implements ItemModel
|
|||
@Override
|
||||
public ItemModel bake(BakingContext context)
|
||||
{
|
||||
ModelBaker modelbaker = context.blockModelBaker();
|
||||
ResolvedModel resolved = modelbaker.getModel(this.baseModel);
|
||||
List<BakedQuad> quads = resolved
|
||||
.bakeTopGeometry(resolved.getTopTextureSlots(), modelbaker,
|
||||
BlockModelRotation.X0_Y0).getAll();
|
||||
|
||||
ItemModel bakedBase = new BlockModelWrapper(List.of(), quads,
|
||||
this.getRenderProperties(context));
|
||||
return new FlowerCrownItemModel(bakedBase, context);
|
||||
return new FlowerCrownItemModel(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveDependencies(Resolver resolver)
|
||||
{
|
||||
resolver.markDependency(this.baseModel);
|
||||
}
|
||||
|
||||
/* A vérifier, pas sûr sûr de celle là Y-Y */
|
||||
private ModelRenderProperties getRenderProperties(
|
||||
ItemModel.BakingContext context)
|
||||
{
|
||||
ModelBaker modelbaker = context.blockModelBaker();
|
||||
ResolvedModel resolvedmodel = modelbaker.getModel(this.baseModel);
|
||||
TextureSlots textureslots = resolvedmodel.getTopTextureSlots();
|
||||
return ModelRenderProperties.fromResolvedModel(modelbaker,
|
||||
resolvedmodel, textureslots);
|
||||
resolver.markDependency(this.base);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,15 +4,19 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import fr.sushi.charmsnfabrics.client.CnFLayers;
|
||||
import fr.sushi.charmsnfabrics.client.model.FlowerCrownModel;
|
||||
import fr.sushi.charmsnfabrics.common.data.SavedColors;
|
||||
import fr.sushi.charmsnfabrics.common.item.FlowerCrown;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.model.geom.EntityModelSet;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.renderer.entity.RenderLayerParent;
|
||||
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
|
||||
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
@ -24,11 +28,15 @@ public class FlowerCrownRenderer implements ICurioRenderer
|
|||
{
|
||||
private final FlowerCrownModel model;
|
||||
|
||||
public FlowerCrownRenderer()
|
||||
public FlowerCrownRenderer(FlowerCrownModel model)
|
||||
{
|
||||
this.model = new FlowerCrownModel(
|
||||
Minecraft.getInstance().getEntityModels()
|
||||
.bakeLayer(CnFLayers.CROWN_LAYER));
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public static FlowerCrownModel createModel()
|
||||
{
|
||||
EntityModelSet modelSet = Minecraft.getInstance().getEntityModels();
|
||||
return new FlowerCrownModel(modelSet.bakeLayer(CnFLayers.CROWN_LAYER));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,8 +2,6 @@ package fr.sushi.charmsnfabrics.common.item;
|
|||
|
||||
import fr.sushi.charmsnfabrics.CharmsAndFabrics;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import top.theillusivec4.curios.api.SlotContext;
|
||||
|
@ -31,6 +29,28 @@ public class FlowerCrown extends Item implements ICurioItem
|
|||
public ResourceLocation getModelTexture()
|
||||
{
|
||||
return ResourceLocation.fromNamespaceAndPath(CharmsAndFabrics.MODID,
|
||||
"textures/models/accessory/flower_crown.png");
|
||||
"textures/models/accessory/flower_crown.png");
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public InteractionResult useOn(UseOnContext context)
|
||||
// {
|
||||
// var player = context.getPlayer();
|
||||
// var level = context.getLevel();
|
||||
// var hand = context.getHand();
|
||||
//
|
||||
// ItemStack stack = player.getItemInHand(hand);
|
||||
// SavedColors comp =
|
||||
// stack.get(CnFRegistries.DataComponents.SAVED_FLOWERS.get());
|
||||
//
|
||||
// stack.set(CnFRegistries.DataComponents.SAVED_FLOWERS.get(),
|
||||
// new SavedColors(List.of(DyeColor.PURPLE, DyeColor.LIME)));
|
||||
// if (comp != null && !comp.flowers().isEmpty())
|
||||
// {
|
||||
// player.displayClientMessage(Component.literal(
|
||||
// comp.flowers().stream().map(DyeColor::toString)
|
||||
// .collect(Collectors.joining(" "))), false);
|
||||
// }
|
||||
// return InteractionResult.SUCCESS;
|
||||
// }
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 141 B |
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 112 B |
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 141 B |
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 362 B |
9
src/main/resources/assets/minecraft/atlases/blocks.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sources": [
|
||||
{
|
||||
"type": "minecraft:directory",
|
||||
"prefix": "flower/",
|
||||
"source": "flower"
|
||||
}
|
||||
]
|
||||
}
|