Minecraft 1.21.4

This commit is contained in:
LexManos committed 2024-12-05 10:22:55 -08:00
1 parent e643d0a11f
commit 041084d1da
219 files changed
+1841 -2621

No files matched your search

@@ -8,6 +8,10 @@ package net.minecraftforge.client;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.shaders.FogShape;
@@ -17,6 +21,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.datafixers.util.Either;
import com.mojang.math.Constants;
import com.mojang.math.Transformation;
import net.minecraft.ChatFormatting;
import net.minecraft.FileUtil;
@@ -26,7 +31,6 @@ import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.ChatComponent;
@@ -57,6 +61,8 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderDefines;
import net.minecraft.client.renderer.ShaderProgram;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.client.renderer.texture.SpriteContents;
@@ -85,6 +91,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceMetadata;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
@@ -139,6 +146,8 @@ import net.minecraftforge.client.extensions.common.IClientMobEffectExtensions;
import net.minecraftforge.client.gui.ClientTooltipComponentManager;
import net.minecraftforge.client.gui.ModMismatchDisconnectedScreen;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.client.model.geometry.GeometryLoaderManager;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.client.textures.ForgeTextureMetadata;
import net.minecraftforge.client.textures.TextureAtlasSpriteLoaderManager;
import net.minecraftforge.common.ForgeConfig;
@@ -175,6 +184,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -281,10 +291,6 @@ public class ForgeHooksClient {
ModLoader.get().postEvent(new RegisterColorHandlersEvent.Block(blockColors));
}
public static void onItemColorsInit(ItemColors itemColors, BlockColors blockColors) {
ModLoader.get().postEvent(new RegisterColorHandlersEvent.Item(itemColors, blockColors));
}
public static Model getArmorModel(HumanoidRenderState state, ItemStack itemStack, EquipmentSlot slot, HumanoidModel<?> _default) {
return IClientItemExtensions.of(itemStack).getGenericArmorModel(state, itemStack, slot, _default);
}
@@ -414,71 +420,27 @@ public class ForgeHooksClient {
return ret;
}
public static void onModifyBakingResult(Map<ModelResourceLocation, BakedModel> models, ModelBakery modelBakery) {
ModLoader.get().postEvent(new ModelEvent.ModifyBakingResult(models, modelBakery));
public static void onModifyBakingResult(ModelBakery modelBakery, ModelBakery.BakingResult results) {
ModLoader.get().postEvent(new ModelEvent.ModifyBakingResult(modelBakery, results));
}
public static void onModelBake(ModelManager modelManager, Map<ModelResourceLocation, BakedModel> models, ModelBakery modelBakery) {
ModLoader.get().postEvent(new ModelEvent.BakingCompleted(modelManager, Collections.unmodifiableMap(models), modelBakery));
public static void onModelBake(ModelManager modelManager, ModelBakery modelBakery) {
ModLoader.get().postEvent(new ModelEvent.BakingCompleted(modelManager, modelBakery));
}
public static TextureAtlasSprite[] getFluidSprites(BlockAndTintGetter level, BlockPos pos, FluidState fluidStateIn) {
IClientFluidTypeExtensions props = IClientFluidTypeExtensions.of(fluidStateIn);
ResourceLocation overlayTexture = props.getOverlayTexture(fluidStateIn, level, pos);
@SuppressWarnings("deprecation")
var BLOCKS = TextureAtlas.LOCATION_BLOCKS;
var atlas = Minecraft.getInstance().getTextureAtlas(BLOCKS);
return new TextureAtlasSprite[] {
Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(props.getStillTexture(fluidStateIn, level, pos)),
Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(props.getFlowingTexture(fluidStateIn, level, pos)),
overlayTexture == null ? null : Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(overlayTexture),
atlas.apply(props.getStillTexture(fluidStateIn, level, pos)),
atlas.apply(props.getFlowingTexture(fluidStateIn, level, pos)),
overlayTexture == null ? null : atlas.apply(overlayTexture),
};
}
public static Material getBlockMaterial(ResourceLocation loc) {
return new Material(InventoryMenu.BLOCK_ATLAS, loc);
}
/*
public static void fillNormal(int[] faceData, Direction facing) {
fillNormal(faceData, facing, false);
}
/**
* internal, relies on fixed format of FaceBakery
* /
// TODO Do we need this?
public static void fillNormal(int[] faceData, Direction facing, boolean calculateNormals) {
Vector3f v2;
if (calculateNormals) {
Vector3f v1 = getVertexPos(faceData, 3);
Vector3f t1 = getVertexPos(faceData, 1);
v2 = getVertexPos(faceData, 2);
Vector3f t2 = getVertexPos(faceData, 0);
v1.sub(t1);
v2.sub(t2);
v2.cross(v1);
v2.normalize();
} else
v2 = new Vector3f(facing.getNormal().getX(), facing.getNormal().getY(), facing.getNormal().getZ());
int x = ((byte) Math.round(v2.x() * 127)) & 0xFF;
int y = ((byte) Math.round(v2.y() * 127)) & 0xFF;
int z = ((byte) Math.round(v2.z() * 127)) & 0xFF;
int normal = x | (y << 0x08) | (z << 0x10);
for(int i = 0; i < 4; i++)
faceData[i * 8 + 7] = normal;
}
*/
private static Vector3f getVertexPos(int[] data, int vertex) {
int idx = vertex * 8;
float x = Float.intBitsToFloat(data[idx]);
float y = Float.intBitsToFloat(data[idx + 1]);
float z = Float.intBitsToFloat(data[idx + 2]);
return new Vector3f(x, y, z);
}
public static boolean calculateFaceWithoutAO(BlockAndTintGetter getter, BlockState state, BlockPos pos, BakedQuad quad, boolean isFaceCubic, float[] brightness, int[] lightmap) {
if (quad.hasAmbientOcclusion())
return false;
@@ -933,4 +895,39 @@ public class ForgeHooksClient {
|| screen.mouseDragged(mouseX, mouseY, mouseButton, dragX, dragY)
|| ForgeEventFactoryClient.onScreenMouseDragPost(screen, mouseX, mouseY, mouseButton, dragX, dragY);
}
public static BlockModel deserializeBlockModel(BlockModel model, List<BlockElement> elements, JsonObject json, JsonDeserializationContext context) {
IUnbakedGeometry<?> geometry = null;
if (json.has("loader")) {
var name = ResourceLocation.parse(GsonHelper.getAsString(json, "loader"));
var loader = GeometryLoaderManager.get(name);
if (loader == null)
throw new JsonParseException(String.format(Locale.ENGLISH, "Model loader '%s' not found. Registered loaders: %s", name, GeometryLoaderManager.getLoaderList()));
geometry = loader.read(json, context);
}
if (geometry != null) {
elements.clear();
model.customData.setCustomGeometry(geometry);
}
if (json.has("transform")) {
JsonElement transform = json.get("transform");
model.customData.setRootTransform(context.deserialize(transform, Transformation.class));
}
if (json.has("render_type")) {
var renderTypeHintName = GsonHelper.getAsString(json, "render_type");
model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName));
}
if (json.has("visibility")) {
var visibility = GsonHelper.getAsJsonObject(json, "visibility");
for (var part : visibility.entrySet())
model.customData.visibilityData.setVisibilityState(part.getKey(), part.getValue().getAsBoolean());
}
return model;
}
}
@@ -12,6 +12,8 @@ import net.minecraft.client.renderer.RenderStateShard.TextureStateShard;
import net.minecraft.client.renderer.RenderType;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.TriState;
@@ -23,17 +25,22 @@ import java.util.function.Function;
import java.util.function.Supplier;
public enum ForgeRenderTypes {
ITEM_LAYERED_SOLID(()-> getItemLayeredSolid(InventoryMenu.BLOCK_ATLAS)),
ITEM_LAYERED_CUTOUT(()-> getItemLayeredCutout(InventoryMenu.BLOCK_ATLAS)),
ITEM_LAYERED_CUTOUT_MIPPED(()-> getItemLayeredCutoutMipped(InventoryMenu.BLOCK_ATLAS)),
ITEM_LAYERED_TRANSLUCENT(()-> getItemLayeredTranslucent(InventoryMenu.BLOCK_ATLAS)),
ITEM_UNSORTED_TRANSLUCENT(()-> getUnsortedTranslucent(InventoryMenu.BLOCK_ATLAS)),
ITEM_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(InventoryMenu.BLOCK_ATLAS)),
ITEM_UNSORTED_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(InventoryMenu.BLOCK_ATLAS, false)),
TRANSLUCENT_ON_PARTICLES_TARGET(() -> getTranslucentParticlesTarget(InventoryMenu.BLOCK_ATLAS));
ITEM_LAYERED_SOLID(()-> getItemLayeredSolid(blockAtlas())),
ITEM_LAYERED_CUTOUT(()-> getItemLayeredCutout(blockAtlas())),
ITEM_LAYERED_CUTOUT_MIPPED(()-> getItemLayeredCutoutMipped(blockAtlas())),
ITEM_LAYERED_TRANSLUCENT(()-> getItemLayeredTranslucent(blockAtlas())),
ITEM_UNSORTED_TRANSLUCENT(()-> getUnsortedTranslucent(blockAtlas())),
ITEM_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(blockAtlas())),
ITEM_UNSORTED_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(blockAtlas(), false)),
TRANSLUCENT_ON_PARTICLES_TARGET(() -> getTranslucentParticlesTarget(blockAtlas()));
public static TriState enableTextTextureLinearFiltering = TriState.FALSE;
@SuppressWarnings("deprecation")
private static final ResourceLocation blockAtlas() {
return TextureAtlas.LOCATION_BLOCKS;
}
/**
* @return A RenderType fit for multi-layer solid item rendering.
*/
@@ -348,7 +355,7 @@ public enum ForgeRenderTypes {
this.mipmap = mipmap.get();
TextureManager manager = Minecraft.getInstance().getTextureManager();
var texture = manager.getTexture(resLoc);
texture.setFilter(this.blur.toBoolean(texture.getDefaultBlur()), this.mipmap);
texture.setFilter(this.blur, this.mipmap);
RenderSystem.setShaderTexture(0, resLoc);
};
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.event;
import java.util.Map;
import net.minecraft.client.renderer.special.SpecialModelRenderer;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.eventbus.api.Event;
public class CreateSpecialBlockRendererEvent extends Event {
private final Map<Block, SpecialModelRenderer.Unbaked> map;
public CreateSpecialBlockRendererEvent(Map<Block, SpecialModelRenderer.Unbaked> map) {
this.map = map;
}
public void register(Block block, SpecialModelRenderer.Unbaked renderer) {
this.map.put(block, renderer);
}
}
@@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
/**
@@ -201,20 +202,11 @@ public abstract class EntityRenderersEvent extends Event implements IModBusEvent
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class CreateSkullModels extends EntityRenderersEvent {
private final ImmutableMap.Builder<Type, SkullModelBase> builder;
private final EntityModelSet entityModelSet;
private final ImmutableMap.Builder<Type, Function<EntityModelSet, SkullModelBase>> builder;
@ApiStatus.Internal
public CreateSkullModels(ImmutableMap.Builder<Type, SkullModelBase> builder, EntityModelSet entityModelSet) {
public CreateSkullModels(ImmutableMap.Builder<Type, Function<EntityModelSet, SkullModelBase>> builder) {
this.builder = builder;
this.entityModelSet = entityModelSet;
}
/**
* {@return the set of entity models}
*/
public EntityModelSet getEntityModelSet() {
return entityModelSet;
}
/**
@@ -228,7 +220,7 @@ public abstract class EntityRenderersEvent extends Event implements IModBusEvent
* {@link EntityModelSet#bakeLayer(ModelLayerLocation)} and pass it to the constructor for
* {@link SkullModel}.
*/
public void registerSkullModel(SkullBlock.Type type, SkullModelBase model) {
public void registerSkullModel(SkullBlock.Type type, Function<EntityModelSet, SkullModelBase> model) {
builder.put(type, model);
}
}
@@ -8,6 +8,8 @@ package net.minecraftforge.client.event;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.Cancelable;
@@ -17,6 +19,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.audio.Channel;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.vertex.PoseStack;
@@ -32,6 +35,8 @@ import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.SkullModelBase;
import net.minecraft.client.model.geom.EntityModelSet;
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.GameRenderer;
@@ -45,6 +50,7 @@ import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.client.renderer.special.SpecialModelRenderer;
import net.minecraft.client.resources.PlayerSkin.Model;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.sounds.SoundEngine;
@@ -57,6 +63,8 @@ import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SkullBlock.Type;
import net.minecraftforge.client.event.sound.PlaySoundSourceEvent;
import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent;
import net.minecraftforge.eventbus.api.Event;
@@ -86,8 +94,9 @@ public final class ForgeEventFactoryClient {
/**
* Post an event to the {@link ModLoader#get()} event bus
*/
private static <T extends Event & IModBusEvent> void postModBus(T e) {
private static <T extends Event & IModBusEvent> T postModBus(T e) {
ML.postEvent(e);
return e;
}
public static void onGatherLayers(Map<EntityType<?>, EntityRenderer<?, ?>> renderers, Map<Model, EntityRenderer<? extends Player, ?>> playerRenderers, Context context) {
@@ -279,4 +288,14 @@ public final class ForgeEventFactoryClient {
public static ComputeFovModifierEvent fireFovModifierEvent(Player entity, float modifier, float scale) {
return fire(new ComputeFovModifierEvent(entity, modifier, scale));
}
public static void onCreateSpecialBlockRenderers(Map<Block, SpecialModelRenderer.Unbaked> map) {
post(new CreateSpecialBlockRendererEvent(map));
}
public static Map<Type, Function<EntityModelSet, SkullModelBase>> onCreateSkullModels() {
var builder = ImmutableMap.<Type, Function<EntityModelSet, SkullModelBase>>builder();
postModBus(new EntityRenderersEvent.CreateSkullModels(builder));
return builder.build();
}
}
@@ -46,20 +46,20 @@ public abstract class ModelEvent extends Event {
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class ModifyBakingResult extends ModelEvent implements IModBusEvent {
private final Map<ModelResourceLocation, BakedModel> models;
private final ModelBakery modelBakery;
private final ModelBakery.BakingResult results;
@ApiStatus.Internal
public ModifyBakingResult(Map<ModelResourceLocation, BakedModel> models, ModelBakery modelBakery) {
this.models = models;
public ModifyBakingResult(ModelBakery modelBakery, ModelBakery.BakingResult results) {
this.modelBakery = modelBakery;
this.results = results;
}
/**
* @return the modifiable registry map of models and their model names
*/
public Map<ModelResourceLocation, BakedModel> getModels() {
return models;
public ModelBakery.BakingResult getResults() {
return results;
}
/**
@@ -83,13 +83,11 @@ public abstract class ModelEvent extends Event {
*/
public static class BakingCompleted extends ModelEvent implements IModBusEvent {
private final ModelManager modelManager;
private final Map<ModelResourceLocation, BakedModel> models;
private final ModelBakery modelBakery;
@ApiStatus.Internal
public BakingCompleted(ModelManager modelManager, Map<ModelResourceLocation, BakedModel> models, ModelBakery modelBakery) {
public BakingCompleted(ModelManager modelManager, ModelBakery modelBakery) {
this.modelManager = modelManager;
this.models = models;
this.modelBakery = modelBakery;
}
@@ -100,13 +98,6 @@ public abstract class ModelEvent extends Event {
return modelManager;
}
/**
* @return an unmodifiable view of the registry map of models and their model names
*/
public Map<ModelResourceLocation, BakedModel> getModels() {
return models;
}
/**
* @return the model loader
*/
@@ -8,11 +8,8 @@ package net.minecraftforge.client.event;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.LogicalSide;
@@ -71,56 +68,6 @@ public abstract class RegisterColorHandlersEvent extends Event implements IModBu
}
}
/**
* Fired for registering item color handlers.
*
* <p>The block colors should only be used for referencing or delegating item colors to their respective block
* colors. Use {@link RegisterColorHandlersEvent.Block} for registering your block color handlers.</p>
*
* <p>This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.</p>
*
* <p>This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus},
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class Item extends RegisterColorHandlersEvent {
private final ItemColors itemColors;
private final BlockColors blockColors;
@ApiStatus.Internal
public Item(ItemColors itemColors, BlockColors blockColors) {
this.itemColors = itemColors;
this.blockColors = blockColors;
}
/**
* {@return the item colors registry}
*
* @see ItemColors#register(ItemColor, ItemLike...)
*/
public ItemColors getItemColors() {
return itemColors;
}
/**
* {@return the block colors registry}
* This should only be used for referencing or delegating item colors to their respective block colors.
*/
public BlockColors getBlockColors() {
return blockColors;
}
/**
* Registers a {@link ItemColor} instance for a set of blocks.
*
* @param itemColor The color provider
* @param items The items
*/
@SuppressWarnings("deprecation")
public void register(ItemColor itemColor, ItemLike... items) {
itemColors.register(itemColor, items);
}
}
/**
* Allows registration of custom {@link ColorResolver} implementations to be used with
* {@link net.minecraft.world.level.BlockAndTintGetter#getBlockTint(BlockPos, ColorResolver)}.
@@ -6,6 +6,8 @@
package net.minecraftforge.client.event;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.textures.ITextureAtlasSpriteLoader;
import net.minecraftforge.eventbus.api.Cancelable;
@@ -16,8 +18,6 @@ import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
/**
* Allows users to register custom {@link ITextureAtlasSpriteLoader texture atlas sprite loaders}.
*
@@ -27,10 +27,10 @@ import java.util.Map;
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public class RegisterTextureAtlasSpriteLoadersEvent extends Event implements IModBusEvent {
private final Map<ResourceLocation, ITextureAtlasSpriteLoader> loaders;
private final BiMap<ResourceLocation, ITextureAtlasSpriteLoader> loaders;
@ApiStatus.Internal
public RegisterTextureAtlasSpriteLoadersEvent(Map<ResourceLocation, ITextureAtlasSpriteLoader> loaders) {
public RegisterTextureAtlasSpriteLoadersEvent(BiMap<ResourceLocation, ITextureAtlasSpriteLoader> loaders) {
this.loaders = loaders;
}
@@ -38,8 +38,10 @@ public class RegisterTextureAtlasSpriteLoadersEvent extends Event implements IMo
* Registers a custom {@link ITextureAtlasSpriteLoader sprite loader}.
*/
public void register(String name, ITextureAtlasSpriteLoader loader) {
@SuppressWarnings("removal")
var key = ResourceLocation.fromNamespaceAndPath(ModLoadingContext.get().getActiveNamespace(), name);
Preconditions.checkArgument(!loaders.containsKey(key), "Sprite loader already registered: " + key);
Preconditions.checkArgument(!loaders.containsValue(loader), "Sprite loader already registered as " + loaders.inverse().get(loader));
loaders.put(key, loader);
}
}
@@ -10,7 +10,6 @@ import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@@ -46,13 +45,6 @@ public class RenderItemInFrameEvent extends Event {
this.packedLight = packedLight;
}
/**
* {@return the item stack being rendered}
*/
public ItemStack getItemStack() {
return getItemFrameState().itemStack;
}
/**
* {@return the item frame entity}
*/
@@ -89,9 +89,11 @@ public interface IForgeBakedModel {
*
* @see #getRenderPasses(ItemStack, boolean)
*/
/*
default List<RenderType> getRenderTypes(ItemStack itemStack, boolean fabulous) {
return List.of(RenderTypeHelper.getFallbackItemRenderType(itemStack, self()));
}
*/
/**
* Gets an ordered list of baked models used to render this model as an item.
@@ -101,7 +103,9 @@ public interface IForgeBakedModel {
*
* @see #getRenderTypes(ItemStack, boolean)
*/
/*
default List<BakedModel> getRenderPasses(ItemStack itemStack, boolean fabulous) {
return List.of(self());
}
*/
}
@@ -1,21 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.extensions;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
public interface IForgeModelBaker {
@Nullable
BakedModel bake(ResourceLocation location, ModelState state, Function<Material, TextureAtlasSprite> sprites);
Function<Material, TextureAtlasSprite> getModelTextureGetter();
}
@@ -5,16 +5,14 @@
package net.minecraftforge.client.extensions.common;
import com.mojang.blaze3d.shaders.FogShape;
import com.mojang.blaze3d.vertex.PoseStack;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Stream;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.FogParameters;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.ScreenEffectRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
@@ -137,10 +135,10 @@ public interface IClientFluidTypeExtensions {
* @param mc the client instance
* @param poseStack the transformations representing the current rendering position
*/
default void renderOverlay(Minecraft mc, PoseStack poseStack) {
default void renderOverlay(Minecraft mc, PoseStack poseStack, MultiBufferSource buffer) {
ResourceLocation texture = this.getRenderOverlayTexture(mc);
if (texture != null)
ScreenEffectRenderer.renderFluid(mc, poseStack, texture);
ScreenEffectRenderer.renderFluid(mc, poseStack, buffer, texture);
}
/**
@@ -6,15 +6,12 @@
package net.minecraftforge.client.extensions.common;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.Model;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.HumanoidArm;
@@ -22,7 +19,6 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.IArmPoseTransformer;
import net.minecraftforge.fml.LogicalSide;
@@ -142,18 +138,6 @@ public interface IClientItemExtensions {
*/
default void renderHelmetOverlay(ItemStack stack, Player player, int width, int height, float partialTick) { }
/**
* Queries this item's renderer.
* <p>
* Only used if {@link BakedModel#isCustomRenderer()} returns {@code true} or {@link BlockState#getRenderShape()}
* returns {@link net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATED}.
* <p>
* By default, returns vanilla's block entity renderer.
*/
default BlockEntityWithoutLevelRenderer getCustomRenderer() {
return Minecraft.getInstance().getItemRenderer().getBlockEntityRenderer();
}
enum FontContext {
/**
* Used to display the amount of items in the {@link ItemStack}.
@@ -103,11 +103,6 @@ public class LoadingErrorScreen extends ErrorScreen {
warnings.forEach(w->addEntry(new LoadingMessageEntry(Component.literal(w.formatToString()))));
}
@Override
protected int getScrollbarPosition() {
return this.getRight() - 6;
}
@Override
public int getRowWidth() {
return this.width;
@@ -22,7 +22,6 @@ import net.minecraftforge.client.ConfigScreenHandler;
import net.minecraftforge.client.gui.widget.ModListWidget;
import net.minecraftforge.client.gui.widget.ScrollPanel;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.maven.artifact.versioning.ComparableVersion;
import com.mojang.blaze3d.systems.RenderSystem;
@@ -58,6 +57,7 @@ import net.minecraft.network.chat.Style;
import org.slf4j.Logger;
public class ModListScreen extends Screen {
private static final ResourceLocation LOGO = ResourceLocation.fromNamespaceAndPath("forge", "mod_logo");
private static String stripControlCodes(String value) { return net.minecraft.util.StringUtil.stripColor(value); }
private static final Logger LOGGER = LogUtils.getLogger();
private enum SortType implements Comparator<IModInfo> {
@@ -378,6 +378,9 @@ public class ModListScreen extends Screen {
updateCache();
}
record Logo(ResourceLocation texture, Size2i size) {}
private static final Logo NONE = new Logo(null, new Size2i(0, 0));
private void updateCache() {
if (selected == null) {
this.configButton.active = false;
@@ -390,8 +393,9 @@ public class ModListScreen extends Screen {
List<String> lines = new ArrayList<>();
VersionChecker.CheckResult vercheck = VersionChecker.getResult(selectedMod);
@SuppressWarnings("resource")
Pair<ResourceLocation, Size2i> logoData = selectedMod.getLogoFile().map(logoFile -> {
var logoData = NONE;
var logoFile = selectedMod.getLogoFile().orElse(null);
if (logoFile != null) {
TextureManager tm = this.minecraft.getTextureManager();
try {
@@ -404,20 +408,26 @@ public class ModListScreen extends Screen {
}
if (logo != null) {
return Pair.of(tm.register("modlogo", new DynamicTexture(logo) {
var texture = new DynamicTexture(logo) {
@Override
public void upload() {
this.bind();
NativeImage td = this.getPixels();
// Use custom "blur" value which controls texture filtering (nearest-neighbor vs linear)
this.getPixels().upload(0, 0, 0, 0, 0, td.getWidth(), td.getHeight(), selectedMod.getLogoBlur(), false, false, false);
var pixels = this.getPixels();
if (pixels != null) {
this.bind();
// Use custom "blur" value which controls texture filtering (nearest-neighbor vs linear)
pixels.upload(0, 0, 0, selectedMod.getLogoBlur());
}
}
}), new Size2i(logo.getWidth(), logo.getHeight()));
};
tm.register(LOGO, texture);
var size = new Size2i(logo.getWidth(), logo.getHeight());
logoData = new Logo(LOGO, size);
}
} catch (IOException e) { }
return Pair.<ResourceLocation, Size2i>of(null, new Size2i(0, 0));
}).orElse(Pair.of(null, new Size2i(0, 0)));
}
lines.add(selectedMod.getDisplayName());
lines.add(ForgeI18n.parseMessage("fml.menu.mods.info.version", MavenVersionStringHelper.artifactVersionToString(selectedMod.getVersion())));
@@ -461,7 +471,7 @@ public class ModListScreen extends Screen {
}
}
modInfo.setInfo(lines, logoData.getLeft(), logoData.getRight());
modInfo.setInfo(lines, logoData.texture(), logoData.size());
}
@Override
@@ -35,11 +35,6 @@ public class ModListWidget extends ObjectSelectionList<ModListWidget.ModEntry> {
this.refreshList();
}
@Override
protected int getScrollbarPosition() {
return this.listWidth;
}
@Override
public int getRowWidth() {
return this.listWidth;
@@ -7,7 +7,6 @@ package net.minecraftforge.client.model;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedOverrides;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -16,7 +15,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.ChunkRenderTypeSet;
@@ -68,11 +66,6 @@ public abstract class BakedModelWrapper<T extends BakedModel> implements BakedMo
return originalModel.usesBlockLight();
}
@Override
public boolean isCustomRenderer() {
return originalModel.isCustomRenderer();
}
@Override
public TextureAtlasSprite getParticleIcon() {
return originalModel.getParticleIcon();
@@ -83,11 +76,6 @@ public abstract class BakedModelWrapper<T extends BakedModel> implements BakedMo
return originalModel.getTransforms();
}
@Override
public BakedOverrides overrides() {
return originalModel.overrides();
}
@Override
public BakedModel applyTransform(ItemDisplayContext cameraTransformType, PoseStack poseStack, boolean applyLeftHandTransform) {
return originalModel.applyTransform(cameraTransformType, poseStack, applyLeftHandTransform);
@@ -114,14 +102,4 @@ public abstract class BakedModelWrapper<T extends BakedModel> implements BakedMo
public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) {
return originalModel.getRenderTypes(state, rand, data);
}
@Override
public List<RenderType> getRenderTypes(ItemStack itemStack, boolean fabulous) {
return originalModel.getRenderTypes(itemStack, fabulous);
}
@Override
public List<BakedModel> getRenderPasses(ItemStack itemStack, boolean fabulous) {
return originalModel.getRenderPasses(itemStack, fabulous);
}
}
@@ -24,6 +24,7 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
@@ -64,9 +65,8 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
}
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
Material particleLocation = context.getMaterial("particle");
TextureAtlasSprite particle = spriteGetter.apply(particleLocation);
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots textures, ModelState modelState) {
var particle = baker.sprites().maybeMissing(textures, "particle");
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
@@ -78,7 +78,7 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
if (!context.isComponentVisible(name, true))
continue;
var model = entry.getValue();
bakedPartsBuilder.put(name, model.bake(baker, spriteGetter, modelState));
bakedPartsBuilder.put(name, model.bake(textures, baker, modelState, model.getAmbientOcclusion(), model.getGuiLight().lightLikeBlock(), model.getTransforms()));
}
var bakedParts = bakedPartsBuilder.build();
@@ -158,11 +158,6 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
return isSideLit;
}
@Override
public boolean isCustomRenderer() {
return false;
}
@Override
public TextureAtlasSprite getParticleIcon() {
return particle;
@@ -181,11 +176,6 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
return ChunkRenderTypeSet.union(sets);
}
@Override
public List<BakedModel> getRenderPasses(ItemStack itemStack, boolean fabulous) {
return itemPasses;
}
@Nullable
public BakedModel getPart(String name) {
return children.get(name);
@@ -223,7 +213,7 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
}
private void addLayer(RenderTypeGroup renderTypes, List<BakedQuad> quads) {
var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle, renderTypes);
var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle/*, renderTypes*/);
quads.forEach(modelBuilder::addUnculledFace);
children.add(modelBuilder.build());
}
@@ -5,27 +5,21 @@
package net.minecraftforge.client.model;
import com.google.common.collect.Maps;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.mojang.math.Transformation;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedOverrides;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.BlockModelRotation;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.ForgeRenderTypes;
import net.minecraftforge.client.RenderTypeGroup;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
@@ -34,18 +28,10 @@ import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.client.model.geometry.StandaloneGeometryBakingContext;
import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.Map;
import java.util.function.Function;
import static net.minecraftforge.client.model.geometry.StandaloneGeometryBakingContext.LOCATION;
/**
* A dynamic fluid container model, capable of re-texturing itself at runtime to match the contained fluid.
* <p>
@@ -85,18 +71,21 @@ public class DynamicFluidContainerModel implements IUnbakedGeometry<DynamicFluid
return new DynamicFluidContainerModel(newFluid, flipGas, coverIsMask, applyFluidLuminosity);
}
@SuppressWarnings("deprecation")
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
Material particleLocation = context.hasMaterial("particle") ? context.getMaterial("particle") : null;
Material baseLocation = context.hasMaterial("base") ? context.getMaterial("base") : null;
Material fluidMaskLocation = context.hasMaterial("fluid") ? context.getMaterial("fluid") : null;
Material coverLocation = context.hasMaterial("cover") ? context.getMaterial("cover") : null;
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots textures, ModelState modelState) {
Material fluidMaskLocation = textures.getMaterial("fluid");
Material stillMaterial = null;
if (fluid != Fluids.EMPTY) {
var stillTexture = IClientFluidTypeExtensions.of(fluid).getStillTexture();
stillMaterial = new Material(TextureAtlas.LOCATION_BLOCKS, stillTexture);
}
TextureAtlasSprite baseSprite = baseLocation != null ? spriteGetter.apply(baseLocation) : null;
TextureAtlasSprite fluidSprite = fluid != Fluids.EMPTY ? spriteGetter.apply(ForgeHooksClient.getBlockMaterial(IClientFluidTypeExtensions.of(fluid).getStillTexture())) : null;
TextureAtlasSprite coverSprite = (coverLocation != null && (!coverIsMask || baseLocation != null)) ? spriteGetter.apply(coverLocation) : null;
TextureAtlasSprite particleSprite = particleLocation != null ? spriteGetter.apply(particleLocation) : null;
var sprites = baker.sprites();
var baseSprite = sprites.maybeMissing(textures, "base");
var fluidSprite = stillMaterial == null ? null : sprites.get(stillMaterial);
var coverSprite = sprites.maybeMissing(textures, "cover"); // (coverLocation != null && (!coverIsMask || baseLocation != null)) ? textures.apply(coverLocation) : null;
var particleSprite = sprites.maybeMissing(textures, "particle");
if (particleSprite == null) particleSprite = fluidSprite;
if (particleSprite == null) particleSprite = baseSprite;
@@ -110,12 +99,12 @@ public class DynamicFluidContainerModel implements IUnbakedGeometry<DynamicFluid
}
// We need to disable GUI 3D and block lighting for this to render properly
var itemContext = StandaloneGeometryBakingContext.builder(context).withGui3d(false).withUseBlockLight(false).build(LOCATION);
var itemContext = StandaloneGeometryBakingContext.builder(context).withGui3d(false).withUseBlockLight(false).build();
var modelBuilder = CompositeModel.Baked.builder(itemContext, particleSprite, /*new ContainedFluidOverrideHandler(baker, itemContext, this),*/ context.getTransforms());
var normalRenderTypes = getLayerRenderTypes(false);
if (baseLocation != null && baseSprite != null) {
if (baseSprite != null) {
// Base texture
var unbaked = UnbakedGeometryHelper.createUnbakedItemElements(0, baseSprite.contents());
var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> baseSprite, modelState);
@@ -123,7 +112,7 @@ public class DynamicFluidContainerModel implements IUnbakedGeometry<DynamicFluid
}
if (fluidMaskLocation != null && fluidSprite != null) {
TextureAtlasSprite templateSprite = spriteGetter.apply(fluidMaskLocation);
TextureAtlasSprite templateSprite = sprites.get(fluidMaskLocation);
if (templateSprite != null) {
// Fluid layer
var transformedState = new SimpleModelState(modelState.getRotation().compose(FLUID_TRANSFORM), modelState.isUvLocked());
@@ -154,17 +143,13 @@ public class DynamicFluidContainerModel implements IUnbakedGeometry<DynamicFluid
return modelBuilder.build();
}
public static final class Loader implements IGeometryLoader<DynamicFluidContainerModel>
{
public static final class Loader implements IGeometryLoader<DynamicFluidContainerModel> {
public static final Loader INSTANCE = new Loader();
private Loader()
{
}
private Loader() { }
@Override
public DynamicFluidContainerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext)
{
public DynamicFluidContainerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) {
if (!jsonObject.has("fluid"))
throw new RuntimeException("Bucket model requires 'fluid' value.");
@@ -180,52 +165,4 @@ public class DynamicFluidContainerModel implements IUnbakedGeometry<DynamicFluid
return new DynamicFluidContainerModel(fluid, flip, coverIsMask, applyFluidLuminosity);
}
}
private static final class ContainedFluidOverrideHandler extends BakedOverrides {
private final Map<String, BakedModel> cache = Maps.newHashMap(); // contains all the baked models since they'll never change
private final BakedOverrides nested;
private final ModelBaker baker;
private final IGeometryBakingContext owner;
private final DynamicFluidContainerModel parent;
private ContainedFluidOverrideHandler(BakedOverrides nested, ModelBaker baker, IGeometryBakingContext owner, DynamicFluidContainerModel parent) {
this.nested = nested;
this.baker = baker;
this.owner = owner;
this.parent = parent;
}
@Override
public BakedModel findOverride(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
BakedModel overridden = nested.findOverride(stack, level, entity, seed);
if (overridden != null)
return overridden;
var fluidStack = FluidUtil.getFluidContained(stack).orElse(null);
if (fluidStack == null)
return null;
Fluid fluid = fluidStack.getFluid();
String name = ForgeRegistries.FLUIDS.getKey(fluid).toString();
if (!cache.containsKey(name)) {
DynamicFluidContainerModel unbaked = this.parent.withFluid(fluid);
BakedModel bakedModel = unbaked.bake(owner, baker, Material::sprite, BlockModelRotation.X0_Y0);//, nested);
cache.put(name, bakedModel);
return bakedModel;
}
return cache.get(name);
}
}
public static class Colors implements ItemColor {
@Override
public int getColor(@NotNull ItemStack stack, int tintIndex) {
if (tintIndex != 1) return 0xFFFFFFFF;
return FluidUtil.getFluidContained(stack)
.map(fluidStack -> IClientFluidTypeExtensions.of(fluidStack.getFluid()).getTintColor(fluidStack))
.orElse(0xFFFFFFFF);
}
}
}
@@ -11,15 +11,11 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.util.GsonHelper;
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
@@ -29,18 +25,17 @@ import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper;
/**
* A model composed of vanilla {@linkplain BlockElement block elements}.
*/
public class ElementsModel extends SimpleUnbakedGeometry<ElementsModel>
{
public class ElementsModel extends SimpleUnbakedGeometry<ElementsModel> {
private final List<BlockElement> elements;
public ElementsModel(List<BlockElement> elements)
{
public ElementsModel(List<BlockElement> elements) {
this.elements = elements;
}
@Override
protected void addQuads(IGeometryBakingContext context, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState)
{
protected void addQuads(IGeometryBakingContext context, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelState) {
//protected void addQuads(IGeometryBakingContext context, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
// If there is a root transform, undo the ModelState transform, apply it, then re-apply the ModelState transform.
// This is necessary because of things like UV locking, which should only respond to the ModelState, and as such
// that is the only transform that should be applied during face bake.
@@ -48,14 +43,13 @@ public class ElementsModel extends SimpleUnbakedGeometry<ElementsModel>
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
postTransform = UnbakedGeometryHelper.applyRootTransform(modelState, rootTransform);
var sprites = baker.sprites();
for (BlockElement element : elements)
{
for (Direction direction : element.faces.keySet())
{
for (var element : elements) {
for (var direction : element.faces.keySet()) {
var face = element.faces.get(direction);
var sprite = spriteGetter.apply(context.getMaterial(face.texture()));
var quad = BlockModel.bakeFace(element, face, sprite, direction, modelState);
var sprite = sprites.maybeMissing(textures, face.texture());
var quad = SimpleBakedModel.bakeFace(element, face, sprite, direction, modelState);
postTransform.processInPlace(quad);
if (face.cullForDirection() == null)
@@ -66,25 +60,18 @@ public class ElementsModel extends SimpleUnbakedGeometry<ElementsModel>
}
}
public static final class Loader implements IGeometryLoader<ElementsModel>
{
public static final class Loader implements IGeometryLoader<ElementsModel> {
public static final Loader INSTANCE = new Loader();
private Loader()
{
}
private Loader() { }
@Override
public ElementsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException
{
public ElementsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException {
if (!jsonObject.has("elements"))
throw new JsonParseException("An element model must have an \"elements\" member.");
List<BlockElement> elements = new ArrayList<>();
for (JsonElement element : GsonHelper.getAsJsonArray(jsonObject, "elements"))
{
elements.add(deserializationContext.deserialize(element, BlockElement.class));
}
return new ElementsModel(elements);
}
@@ -7,17 +7,16 @@ package net.minecraftforge.client.model;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.client.RenderTypeGroup;
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
@@ -37,20 +36,20 @@ public class EmptyModel extends SimpleUnbakedGeometry<EmptyModel> {
private EmptyModel() { }
@Override
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform) {
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelTransform) {
// NO-OP
}
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots spriteGetter, ModelState modelState) {
return BAKED;
}
private static class Baked extends SimpleBakedModel {
private static final Material MISSING_TEXTURE = new Material(InventoryMenu.BLOCK_ATLAS, MissingTextureAtlasSprite.getLocation());
private static final Material MISSING_TEXTURE = new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation());
public Baked() {
super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, RenderTypeGroup.EMPTY);
super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS/*, RenderTypeGroup.EMPTY*/);
}
@Override
@@ -1,101 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.model;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.math.Transformation;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockElementFace;
import net.minecraft.client.renderer.block.model.BlockFaceUV;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemOverride;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraftforge.client.model.geometry.GeometryLoaderManager;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.common.util.TransformationHelper;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* A version of {@link BlockModel.Deserializer} capable of deserializing models with custom loaders, as well as other
* changes introduced to the spec by Forge.
*/
public class ExtendedBlockModelDeserializer extends BlockModel.Deserializer
{
public static final Gson INSTANCE = (new GsonBuilder())
.registerTypeAdapter(BlockModel.class, new ExtendedBlockModelDeserializer())
.registerTypeAdapter(BlockElement.class, new BlockElement.Deserializer())
.registerTypeAdapter(BlockElementFace.class, new BlockElementFace.Deserializer())
.registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer())
.registerTypeAdapter(ItemTransform.class, new ItemTransform.Deserializer())
.registerTypeAdapter(ItemTransforms.class, new ItemTransforms.Deserializer())
.registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer())
.registerTypeAdapter(Transformation.class, new TransformationHelper.Deserializer())
.create();
public BlockModel deserialize(JsonElement element, Type targetType, JsonDeserializationContext deserializationContext) throws JsonParseException
{
BlockModel model = super.deserialize(element, targetType, deserializationContext);
JsonObject jsonobject = element.getAsJsonObject();
IUnbakedGeometry<?> geometry = deserializeGeometry(deserializationContext, jsonobject);
List<BlockElement> elements = model.getElements();
if (geometry != null)
{
elements.clear();
model.customData.setCustomGeometry(geometry);
}
if (jsonobject.has("transform"))
{
JsonElement transform = jsonobject.get("transform");
model.customData.setRootTransform(deserializationContext.deserialize(transform, Transformation.class));
}
if (jsonobject.has("render_type"))
{
var renderTypeHintName = GsonHelper.getAsString(jsonobject, "render_type");
model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName));
}
if (jsonobject.has("visibility"))
{
JsonObject visibility = GsonHelper.getAsJsonObject(jsonobject, "visibility");
for (Map.Entry<String, JsonElement> part : visibility.entrySet())
{
model.customData.visibilityData.setVisibilityState(part.getKey(), part.getValue().getAsBoolean());
}
}
return model;
}
@Nullable
public static IUnbakedGeometry<?> deserializeGeometry(JsonDeserializationContext deserializationContext, JsonObject object) throws JsonParseException
{
if (!object.has("loader"))
return null;
var name = ResourceLocation.parse(GsonHelper.getAsString(object, "loader"));
var loader = GeometryLoaderManager.get(name);
if (loader == null)
throw new JsonParseException(String.format(Locale.ENGLISH, "Model loader '%s' not found. Registered loaders: %s", name, GeometryLoaderManager.getLoaderList()));
return loader.read(object, deserializationContext);
}
}
@@ -11,25 +11,26 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.core.Direction;
import net.minecraftforge.client.RenderTypeGroup;
import java.util.List;
/**
* Base interface for any object that collects culled and unculled faces and bakes them into a model.
* <p>
* Provides a generic base implementation via {@link #of(boolean, boolean, boolean, ItemTransforms, ItemOverrides, TextureAtlasSprite, RenderTypeGroup)}
* Provides a generic base implementation via {@link #of(boolean, boolean, boolean, ItemTransforms, ItemOverrides, TextureAtlasSprite)}
* and a quad-collecting alternative via {@link #collecting(List)}.
*/
public interface IModelBuilder<T extends IModelBuilder<T>> {
/**
* Creates a new model builder that uses the provided attributes in the final baked model.
*/
static IModelBuilder<?> of(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
ItemTransforms transforms, TextureAtlasSprite particle,
RenderTypeGroup renderTypes
static IModelBuilder<?> of(
boolean hasAmbientOcclusion,
boolean usesBlockLight,
boolean isGui3d,
ItemTransforms transforms,
TextureAtlasSprite particle
){
return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes);
return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle);
}
/**
@@ -48,13 +49,12 @@ public interface IModelBuilder<T extends IModelBuilder<T>> {
class Simple implements IModelBuilder<Simple> {
private final SimpleBakedModel.Builder builder;
private final RenderTypeGroup renderTypes;
private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
ItemTransforms transforms, TextureAtlasSprite particle, RenderTypeGroup renderTypes
private Simple(
boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
ItemTransforms transforms, TextureAtlasSprite particle
) {
this.builder = new SimpleBakedModel.Builder(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms).particle(particle);
this.renderTypes = renderTypes;
}
@Override
@@ -72,7 +72,7 @@ public interface IModelBuilder<T extends IModelBuilder<T>> {
@Deprecated
@Override
public BakedModel build() {
return builder.renderTypes(renderTypes).build();
return builder.build();
}
}
@@ -13,7 +13,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
@@ -27,8 +27,6 @@ import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
/**
* Forge reimplementation of vanilla's {@link ItemModelGenerator}, i.e. builtin/generated models with some tweaks:
* - Represented as {@link IUnbakedGeometry} so it can be baked as usual instead of being special-cased
@@ -46,17 +44,19 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel> {
}
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots spriteGetter, ModelState modelState) {
if (textures == null) {
ImmutableList.Builder<Material> builder = ImmutableList.builder();
for (int i = 0; context.hasMaterial("layer" + i); i++)
builder.add(context.getMaterial("layer" + i));
int i = 0;
Material material;
while ((material = spriteGetter.getMaterial("layer" + i++)) != null) {
builder.add(material);
}
textures = builder.build();
}
TextureAtlasSprite particle = spriteGetter.apply(
context.hasMaterial("particle") ? context.getMaterial("particle") : textures.get(0)
);
Material particleMaterial = spriteGetter.getMaterial("particle");
var particle = baker.sprites().get(particleMaterial == null ? textures.get(0) : particleMaterial);
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
modelState = UnbakedGeometryHelper.composeRootTransformIntoModelState(modelState, rootTransform);
@@ -64,7 +64,7 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel> {
var normalRenderTypes = new RenderTypeGroup(RenderType.translucent(), ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get());
var builder = CompositeModel.Baked.builder(context, particle, context.getTransforms());
for (int i = 0; i < textures.size(); i++) {
var sprite = spriteGetter.apply(textures.get(i));
var sprite = baker.sprites().get(textures.get(i));
var unbaked = UnbakedGeometryHelper.createUnbakedItemElements(i, sprite.contents());
var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, modelState);
var renderTypeName = renderTypeNames.get(i);
@@ -13,14 +13,13 @@ import com.mojang.blaze3d.vertex.PoseStack;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
@@ -49,16 +48,17 @@ public class SeparateTransformsModel implements IUnbakedGeometry<SeparateTransfo
this.perspectives = perspectives;
}
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots textures, ModelState modelState) {
return new Baked(
context.useAmbientOcclusion(),
context.isGui3d(),
context.useBlockLight(),
spriteGetter.apply(context.getMaterial("particle")),
baseModel.bake(spriteGetter, modelState, context.useBlockLight()),
baker.sprites().maybeMissing(textures, "particle"),
baseModel.bake(textures, baker, modelState),
ImmutableMap.copyOf(Maps.transformValues(perspectives, value -> {
return value.bake(spriteGetter, modelState, context.useBlockLight());
return value.bake(textures, baker, modelState, context.useBlockLight(), value.getGuiLight().lightLikeBlock(), value.getTransforms());
}))
);
}
@@ -107,11 +107,6 @@ public class SeparateTransformsModel implements IUnbakedGeometry<SeparateTransfo
return isSideLit;
}
@Override
public boolean isCustomRenderer() {
return false;
}
@Override
public TextureAtlasSprite getParticleIcon() {
return particle;
@@ -23,12 +23,12 @@ import com.mojang.math.Transformation;
import com.mojang.serialization.JsonOps;
import net.minecraft.client.renderer.block.model.BlockFaceUV;
import net.minecraft.client.renderer.block.model.BlockModel.GuiLight;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockElementFace;
import net.minecraft.client.renderer.block.model.BlockElementRotation;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.resources.model.UnbakedModel.GuiLight;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
@@ -41,18 +42,20 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
this.owner = owner;
}
@Override
public String getModelName() {
return owner.name;
}
public boolean hasCustomGeometry() {
return getCustomGeometry() != null;
}
private BlockGeometryBakingContext parentContext() {
return owner.parent instanceof BlockModel block ? block.customData : null;
}
@Nullable
public IUnbakedGeometry<?> getCustomGeometry() {
return owner.parent != null && customGeometry == null ? owner.parent.customData.getCustomGeometry() : customGeometry;
if (customGeometry != null)
return customGeometry;
var pctx = parentContext();
return pctx == null ? null : pctx.getCustomGeometry();
}
public void setCustomGeometry(IUnbakedGeometry<?> geometry) {
@@ -61,19 +64,10 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
@Override
public boolean isComponentVisible(String part, boolean fallback) {
return owner.parent != null && !visibilityData.hasCustomVisibility(part) ?
owner.parent.customData.isComponentVisible(part, fallback) :
visibilityData.isVisible(part, fallback);
}
@Override
public boolean hasMaterial(String name) {
return owner.hasTexture(name);
}
@Override
public Material getMaterial(String name) {
return owner.getMaterial(name);
var pctx = parentContext();
if (pctx == null || visibilityData.hasCustomVisibility(part))
return visibilityData.isVisible(part, fallback);
return pctx.isComponentVisible(part, fallback);
}
@Override
@@ -88,7 +82,7 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
@Override
public boolean useAmbientOcclusion() {
return owner.hasAmbientOcclusion();
return owner.getAmbientOcclusion();
}
@Override
@@ -100,7 +94,8 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
public Transformation getRootTransform() {
if (rootTransform != null)
return rootTransform;
return owner.parent != null ? owner.parent.customData.getRootTransform() : Transformation.identity();
var pctx = parentContext();
return pctx == null ? Transformation.identity() : pctx.getRootTransform();
}
public void setRootTransform(Transformation rootTransform) {
@@ -112,7 +107,8 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
public ResourceLocation getRenderTypeHint() {
if (renderTypeHint != null)
return renderTypeHint;
return owner.parent != null ? owner.parent.customData.getRenderTypeHint() : null;
var pctx = parentContext();
return pctx == null ? null: pctx.getRenderTypeHint();
}
public void setRenderTypeHint(ResourceLocation renderTypeHint) {
@@ -131,11 +127,11 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext {
this.gui3d = other.gui3d;
}
public BakedModel bake(ModelBaker baker, Function<Material, TextureAtlasSprite> bakedTextureGetter, ModelState modelTransform) {
public BakedModel bake(ModelBaker baker, TextureSlots textures, ModelState modelTransform) {
IUnbakedGeometry<?> geometry = getCustomGeometry();
if (geometry == null)
throw new IllegalStateException("Can not use custom baking without custom geometry");
return geometry.bake(this, baker, bakedTextureGetter, modelTransform);
return geometry.bake(this, baker, textures, modelTransform);
}
public static class VisibilityData {
@@ -22,27 +22,6 @@ import org.jetbrains.annotations.Nullable;
* @see BlockGeometryBakingContext
*/
public interface IGeometryBakingContext {
/**
* {@return the name of the model being baked for logging and caching purposes.}
*/
String getModelName();
/**
* Checks if a material is present in the model.
*
* @param name The name of the material
* @return true if the material is present, false otherwise
*/
boolean hasMaterial(String name);
/**
* Resolves the final texture name, taking into account texture aliases and replacements.
*
* @param name The name of the material
* @return The material, or the missing texture if not found
*/
Material getMaterial(String name);
/**
* {@return true if this model should render in 3D in a GUI, false otherwise}
*/
@@ -9,9 +9,8 @@ import java.util.Set;
import java.util.function.Function;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
@@ -19,17 +18,17 @@ import net.minecraft.client.resources.model.UnbakedModel;
/**
* General interface for any model that can be baked, superset of vanilla {@link UnbakedModel}.
* <p>
* Instances of this class ar usually created via {@link IGeometryLoader}.
* Instances of this class are usually created via {@link IGeometryLoader}.
*
* @see IGeometryLoader
* @see IGeometryBakingContext
*/
public interface IUnbakedGeometry<T extends IUnbakedGeometry<T>> {
BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState);
BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots spriteGetter, ModelState modelState);
/**
* Resolve parents of nested {@link BlockModel}s which are later used in
* {@link IUnbakedGeometry#bake(IGeometryBakingContext, ModelBaker, Function, ModelState)}
* {@link IUnbakedGeometry#bake(IGeometryBakingContext, ModelBaker, TextureSlots, ModelState)}
* via {@link BlockModel#resolveParents(Function)}
*/
default void resolveDependencies(UnbakedModel.Resolver resolver, IGeometryBakingContext context) { }
@@ -5,15 +5,11 @@
package net.minecraftforge.client.model.geometry;
import java.util.function.Function;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.RenderTypeGroup;
import net.minecraftforge.client.model.IModelBuilder;
/**
@@ -22,18 +18,18 @@ import net.minecraftforge.client.model.IModelBuilder;
*/
public abstract class SimpleUnbakedGeometry<T extends SimpleUnbakedGeometry<T>> implements IUnbakedGeometry<T> {
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
TextureAtlasSprite particle = spriteGetter.apply(context.getMaterial("particle"));
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, TextureSlots textures, ModelState modelState) {
var particle = baker.sprites().maybeMissing(textures, "particle");
var renderTypeHint = context.getRenderTypeHint();
var renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY;
//var renderTypeHint = context.getRenderTypeHint();
//var renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY;
IModelBuilder<?> builder = IModelBuilder.of(context.useAmbientOcclusion(), context.useBlockLight(), context.isGui3d(),
context.getTransforms(), particle, renderTypes);
context.getTransforms(), particle/*, renderTypes*/);
addQuads(context, builder, baker, spriteGetter, modelState);
addQuads(context, builder, baker, textures, modelState);
return builder.build();
}
protected abstract void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform);
protected abstract void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelTransform);
}
@@ -5,21 +5,13 @@
package net.minecraftforge.client.model.geometry;
import com.google.common.base.Predicates;
import com.mojang.math.Transformation;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.resources.model.Material;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.InventoryMenu;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* A {@linkplain IGeometryBakingContext geometry baking context} that is not bound to block/item model loading.
@@ -27,23 +19,8 @@ import java.util.function.Predicate;
public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
public static final ResourceLocation LOCATION = ResourceLocation.fromNamespaceAndPath("forge", "standalone");
public static final StandaloneGeometryBakingContext INSTANCE = create(LOCATION);
public static final StandaloneGeometryBakingContext INSTANCE = builder().build();
public static StandaloneGeometryBakingContext create(ResourceLocation modelName) {
return builder().build(modelName);
}
public static StandaloneGeometryBakingContext create(Map<String, ResourceLocation> textures) {
return create(LOCATION, textures);
}
public static StandaloneGeometryBakingContext create(ResourceLocation modelName, Map<String, ResourceLocation> textures) {
return builder().withTextures(textures, MissingTextureAtlasSprite.getLocation()).build(modelName);
}
private final ResourceLocation modelName;
private final Predicate<String> materialCheck;
private final Function<String, Material> materialLookup;
private final boolean isGui3d;
private final boolean useBlockLight;
private final boolean useAmbientOcclusion;
@@ -54,16 +31,12 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
private final BiPredicate<String, Boolean> visibilityTest;
private StandaloneGeometryBakingContext(
ResourceLocation modelName, Predicate<String> materialCheck,
Function<String, Material> materialLookup, boolean isGui3d,
boolean isGui3d,
boolean useBlockLight, boolean useAmbientOcclusion,
ItemTransforms transforms, Transformation rootTransform,
@Nullable ResourceLocation renderTypeHint,
BiPredicate<String, Boolean> visibilityTest
) {
this.modelName = modelName;
this.materialCheck = materialCheck;
this.materialLookup = materialLookup;
this.isGui3d = isGui3d;
this.useBlockLight = useBlockLight;
this.useAmbientOcclusion = useAmbientOcclusion;
@@ -73,21 +46,6 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
this.visibilityTest = visibilityTest;
}
@Override
public String getModelName() {
return modelName.toString();
}
@Override
public boolean hasMaterial(String name) {
return materialCheck.test(name);
}
@Override
public Material getMaterial(String name) {
return materialLookup.apply(name);
}
@Override
public boolean isGui3d() {
return isGui3d;
@@ -133,9 +91,6 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
}
public static final class Builder {
private static final Material NO_MATERIAL = new Material(InventoryMenu.BLOCK_ATLAS, MissingTextureAtlasSprite.getLocation());
private Predicate<String> materialCheck = Predicates.alwaysFalse();
private Function<String, Material> materialLookup = $ -> NO_MATERIAL;
private boolean isGui3d = true;
private boolean useBlockLight = true;
private boolean useAmbientOcclusion = true;
@@ -148,8 +103,6 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
private Builder() { }
private Builder(IGeometryBakingContext parent) {
this.materialCheck = parent::hasMaterial;
this.materialLookup = parent::getMaterial;
this.isGui3d = parent.isGui3d();
this.useBlockLight = parent.useBlockLight();
this.useAmbientOcclusion = parent.useAmbientOcclusion();
@@ -159,22 +112,6 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
this.visibilityTest = parent::isComponentVisible;
}
public Builder withTextures(Map<String, ResourceLocation> textures, ResourceLocation defaultTexture) {
return withTextures(InventoryMenu.BLOCK_ATLAS, textures, defaultTexture);
}
public Builder withTextures(ResourceLocation atlasLocation, Map<String, ResourceLocation> textures, ResourceLocation defaultTexture) {
this.materialCheck = textures::containsKey;
this.materialLookup = name -> new Material(atlasLocation, textures.getOrDefault(name, defaultTexture));
return this;
}
public Builder withMaterials(Map<String, Material> materials, Material defaultMaterial) {
this.materialCheck = materials::containsKey;
this.materialLookup = name -> materials.getOrDefault(name, defaultMaterial);
return this;
}
public Builder withGui3d(boolean isGui3d) {
this.isGui3d = isGui3d;
return this;
@@ -211,8 +148,8 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext {
return this;
}
public StandaloneGeometryBakingContext build(ResourceLocation modelName) {
return new StandaloneGeometryBakingContext(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest);
public StandaloneGeometryBakingContext build() {
return new StandaloneGeometryBakingContext(isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest);
}
}
}
@@ -12,11 +12,13 @@ import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockElementFace;
import net.minecraft.client.renderer.block.model.BlockFaceUV;
import net.minecraft.client.renderer.block.model.FaceBakery;
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
@@ -25,6 +27,8 @@ import net.minecraftforge.client.model.IModelBuilder;
import net.minecraftforge.client.model.IQuadTransformer;
import net.minecraftforge.client.model.QuadTransformers;
import net.minecraftforge.client.model.SimpleModelState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
@@ -39,6 +43,7 @@ import java.util.regex.Pattern;
/**
* Helper for dealing with unbaked models and geometries.
*/
@ApiStatus.Internal
public class UnbakedGeometryHelper {
private static final FaceBakery FACE_BAKERY = new FaceBakery();
@@ -64,11 +69,11 @@ public class UnbakedGeometryHelper {
* <p>
* The target atlas will always be {@link InventoryMenu#BLOCK_ATLAS}.
*/
public static Material resolveDirtyMaterial(@Nullable String tex, IGeometryBakingContext owner) {
public static Material resolveDirtyMaterial(@Nullable String tex, TextureSlots textures) {
if (tex == null)
return new Material(InventoryMenu.BLOCK_ATLAS, MissingTextureAtlasSprite.getLocation());
return new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation());
if (tex.startsWith("#"))
return owner.getMaterial(tex);
return textures.getMaterial(tex);
// Attempt to convert a common (windows/linux/mac) filesystem path to a ResourceLocation.
// This makes no promises, if it doesn't work, too bad, fix your mtl file.
@@ -79,9 +84,10 @@ public class UnbakedGeometryHelper {
tex = namespace != null ? namespace + ":" + path : path;
}
return new Material(InventoryMenu.BLOCK_ATLAS, ResourceLocation.parse(tex));
return new Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.parse(tex));
}
private static final ItemModelGenerator ITEM_MODEL_GENERATOR = new ItemModelGenerator();
/**
* Creates a list of {@linkplain BlockElement block elements} in the shape of the specified sprite contents.
* These can later be baked using the same, or another texture.
@@ -89,7 +95,7 @@ public class UnbakedGeometryHelper {
* The {@link Direction#NORTH} and {@link Direction#SOUTH} faces take up the whole surface.
*/
public static List<BlockElement> createUnbakedItemElements(int layerIndex, SpriteContents spriteContents) {
return ModelBakery.ITEM_MODEL_GENERATOR.processFrames(layerIndex, "layer" + layerIndex, spriteContents);
return ITEM_MODEL_GENERATOR.processFrames(layerIndex, "layer" + layerIndex, spriteContents);
}
/**
@@ -162,7 +168,7 @@ public class UnbakedGeometryHelper {
public static void bakeElements(IModelBuilder<?> builder, List<BlockElement> elements, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState) {
for (BlockElement element : elements) {
element.faces.forEach((side, face) -> {
var sprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, ResourceLocation.parse(face.texture())));
var sprite = spriteGetter.apply(new Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.parse(face.texture())));
var quad = bakeElementFace(element, face, sprite, side, modelState, element.lightEmission);
if (face.cullForDirection() == null)
builder.addUnculledFace(quad);
@@ -11,11 +11,11 @@ import com.google.common.collect.Sets;
import com.mojang.math.Transformation;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
@@ -43,9 +43,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* A model loaded from an OBJ file.
@@ -53,14 +51,13 @@ import java.util.stream.Stream;
* Supports positions, texture coordinates, normals and colors. The {@link ObjMaterialLibrary material library}
* has support for numerous features, including support for {@link ResourceLocation} textures (non-standard).
*/
public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
{
public class ObjModel extends SimpleUnbakedGeometry<ObjModel> {
private static final Vector4f COLOR_WHITE = new Vector4f(1, 1, 1, 1);
private static final Vec2[] DEFAULT_COORDS = {
new Vec2(0, 0),
new Vec2(0, 1),
new Vec2(1, 1),
new Vec2(1, 0),
new Vec2(0, 0),
new Vec2(0, 1),
new Vec2(1, 1),
new Vec2(1, 0),
};
private final Map<String, ModelGroup> parts = Maps.newLinkedHashMap();
@@ -81,8 +78,7 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
public final ResourceLocation modelLocation;
private ObjModel(ModelSettings settings)
{
private ObjModel(ModelSettings settings) {
this.modelLocation = settings.modelLocation;
this.automaticCulling = settings.automaticCulling;
this.shadeQuads = settings.shadeQuads;
@@ -91,8 +87,7 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
this.mtlOverride = settings.mtlOverride;
}
public static ObjModel parse(ObjTokenizer tokenizer, ModelSettings settings) throws IOException
{
public static ObjModel parse(ObjTokenizer tokenizer, ModelSettings settings) throws IOException {
var modelLocation = settings.modelLocation;
var materialLibraryOverrideLocation = settings.mtlOverride;
var model = new ObjModel(settings);
@@ -115,8 +110,7 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
boolean objAboveGroup = false;
if (materialLibraryOverrideLocation != null)
{
if (materialLibraryOverrideLocation != null) {
String lib = materialLibraryOverrideLocation;
if (lib.contains(":"))
mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(ResourceLocation.parse(lib));
@@ -125,12 +119,9 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
}
String[] line;
while ((line = tokenizer.readAndSplitLine(true)) != null)
{
switch (line[0])
{
case "mtllib": // Loads material library
{
while ((line = tokenizer.readAndSplitLine(true)) != null) {
switch (line[0]) {
case "mtllib": { // Loads material library
if (materialLibraryOverrideLocation != null)
break;
@@ -141,28 +132,18 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(ResourceLocation.fromNamespaceAndPath(modelDomain, modelPath + lib));
break;
}
case "usemtl": // Sets the current material (starts new mesh)
{
case "usemtl": { // Sets the current material (starts new mesh)
String mat = Arrays.asList(Arrays.copyOfRange(line, 1, line.length)).stream().collect(Collectors.joining(" "));
ObjMaterialLibrary.Material newMat = mtllib.getMaterial(mat);
if (!Objects.equals(newMat, currentMat))
{
if (!Objects.equals(newMat, currentMat)) {
currentMat = newMat;
if (currentMesh != null && currentMesh.mat == null && currentMesh.faces.isEmpty())
{
currentMesh.mat = currentMat;
}
else
{
// Start new mesh
else // Start new mesh
currentMesh = null;
}
}
break;
}
case "v": // Vertex
model.positions.add(parseVector4To3(line));
break;
@@ -175,20 +156,13 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
case "vc": // Vertex color (non-standard)
model.colors.add(parseVector4(line));
break;
case "f": // Face
{
if (currentMesh == null)
{
case "f": { // Face
if (currentMesh == null) {
currentMesh = model.new ModelMesh(currentMat, currentSmoothingGroup);
if (currentObject != null)
{
currentObject.meshes.add(currentMesh);
}
else
{
if (currentGroup == null)
{
else {
if (currentGroup == null) {
currentGroup = model.new ModelGroup("");
model.parts.put("", currentGroup);
}
@@ -197,65 +171,39 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
}
int[][] vertices = new int[line.length - 1][];
for (int i = 0; i < vertices.length; i++)
{
for (int i = 0; i < vertices.length; i++) {
String vertexData = line[i + 1];
String[] vertexParts = vertexData.split("/");
int[] vertex = Arrays.stream(vertexParts).mapToInt(num -> num == null || num.isEmpty() ? 0 : Integer.parseInt(num)).toArray();
if (vertex[0] < 0) vertex[0] = model.positions.size() + vertex[0];
else vertex[0]--;
if (vertex.length > 1)
{
if (vertex[1] < 0) vertex[1] = model.texCoords.size() + vertex[1];
else vertex[1]--;
if (vertex.length > 2)
{
if (vertex[2] < 0) vertex[2] = model.normals.size() + vertex[2];
else vertex[2]--;
if (vertex.length > 3)
{
if (vertex[3] < 0) vertex[3] = model.colors.size() + vertex[3];
else vertex[3]--;
}
}
for (int x = 0; x < 4 && x < vertex.length; x++) {
if (vertex[x] < 0)
vertex[x] = model.positions.size() + vertex[x];
else
vertex[x]--;
}
vertices[i] = vertex;
}
currentMesh.faces.add(vertices);
break;
}
case "s": // Smoothing group (starts new mesh)
{
case "s": { // Smoothing group (starts new mesh)
String smoothingGroup = "off".equals(line[1]) ? null : line[1];
if (!Objects.equals(currentSmoothingGroup, smoothingGroup))
{
if (!Objects.equals(currentSmoothingGroup, smoothingGroup)) {
currentSmoothingGroup = smoothingGroup;
if (currentMesh != null && currentMesh.smoothingGroup == null && currentMesh.faces.isEmpty())
{
currentMesh.smoothingGroup = currentSmoothingGroup;
}
else
{
// Start new mesh
else // Start new mesh
currentMesh = null;
}
}
break;
}
case "g":
{
case "g": {
String name = line[1];
if (objAboveGroup)
{
if (objAboveGroup) {
currentObject = model.new ModelObject(currentGroup.name() + "/" + name);
currentGroup.parts.put(name, currentObject);
}
else
{
} else {
currentGroup = model.new ModelGroup(name);
model.parts.put(name, currentGroup);
currentObject = null;
@@ -264,20 +212,15 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
currentMesh = null;
break;
}
case "o":
{
case "o": {
String name = line[1];
if (objAboveGroup || currentGroup == null)
{
if (objAboveGroup || currentGroup == null) {
objAboveGroup = true;
currentGroup = model.new ModelGroup(name);
model.parts.put(name, currentGroup);
currentObject = null;
}
else
{
} else {
currentObject = model.new ModelObject(currentGroup.name() + "/" + name);
currentGroup.parts.put(name, currentObject);
}
@@ -290,30 +233,25 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
return model;
}
private static Vector3f parseVector4To3(String[] line)
{
private static Vector3f parseVector4To3(String[] line) {
Vector4f vec4 = parseVector4(line);
return new Vector3f(
vec4.x() / vec4.w(),
vec4.y() / vec4.w(),
vec4.z() / vec4.w()
vec4.x() / vec4.w(),
vec4.y() / vec4.w(),
vec4.z() / vec4.w()
);
}
private static Vec2 parseVector2(String[] line)
{
return switch (line.length)
{
private static Vec2 parseVector2(String[] line) {
return switch (line.length) {
case 1 -> new Vec2(0, 0);
case 2 -> new Vec2(Float.parseFloat(line[1]), 0);
default -> new Vec2(Float.parseFloat(line[1]), Float.parseFloat(line[2]));
};
}
private static Vector3f parseVector3(String[] line)
{
return switch (line.length)
{
private static Vector3f parseVector3(String[] line) {
return switch (line.length) {
case 1 -> new Vector3f();
case 2 -> new Vector3f(Float.parseFloat(line[1]), 0, 0);
case 3 -> new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0);
@@ -321,10 +259,8 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
};
}
static Vector4f parseVector4(String[] line)
{
return switch (line.length)
{
static Vector4f parseVector4(String[] line) {
return switch (line.length) {
case 1 -> new Vector4f();
case 2 -> new Vector4f(Float.parseFloat(line[1]), 0, 0, 1);
case 3 -> new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0, 1);
@@ -334,20 +270,19 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
}
@Override
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform)
{
parts.values().stream().filter(part -> owner.isComponentVisible(part.name(), true))
.forEach(part -> part.addQuads(owner, modelBuilder, baker, spriteGetter, modelTransform, modelLocation));
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelTransform) {
for (var part : parts.values()) {
if (owner.isComponentVisible(part.name(), true))
part.addQuads(owner, modelBuilder, baker, textures, modelTransform, modelLocation);
}
}
public Set<String> getRootComponentNames()
{
public Set<String> getRootComponentNames() {
return rootComponentNames;
}
@Override
public Set<String> getConfigurableComponentNames()
{
public Set<String> getConfigurableComponentNames() {
if (allComponentNames != null)
return allComponentNames;
var names = new HashSet<String>();
@@ -356,16 +291,13 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
return allComponentNames = Collections.unmodifiableSet(names);
}
private Pair<BakedQuad, Direction> makeQuad(int[][] indices, int tintIndex, Vector4f colorTint, Vector4f ambientColor, TextureAtlasSprite texture, Transformation transform)
{
private Pair<BakedQuad, Direction> makeQuad(int[][] indices, int tintIndex, Vector4f colorTint, Vector4f ambientColor, TextureAtlasSprite texture, Transformation transform) {
boolean needsNormalRecalculation = false;
for (int[] ints : indices)
{
needsNormalRecalculation |= ints.length < 3;
}
Vector3f faceNormal = new Vector3f();
if (needsNormalRecalculation)
{
if (needsNormalRecalculation) {
Vector3f a = positions.get(indices[0][0]);
Vector3f ab = positions.get(indices[1][0]);
Vector3f ac = positions.get(indices[2][0]);
@@ -384,16 +316,12 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
quadBaker.setTintIndex(tintIndex);
int uv2 = 0;
if (emissiveAmbient)
{
if (emissiveAmbient) {
int fakeLight = (int) ((ambientColor.x() + ambientColor.y() + ambientColor.z()) * 15 / 3.0f);
uv2 = LightTexture.pack(fakeLight, fakeLight);
quadBaker.setShade(fakeLight == 0 && shadeQuads);
}
else
{
} else
quadBaker.setShade(shadeQuads);
}
boolean hasTransform = !transform.isIdentity();
// The incoming transform is referenced on the center of the block, but our coords are referenced on the corner
@@ -402,16 +330,14 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
Vector4f[] pos = new Vector4f[4];
Vector3f[] norm = new Vector3f[4];
for (int i = 0; i < 4; i++)
{
for (int i = 0; i < 4; i++) {
int[] index = indices[Math.min(i, indices.length - 1)];
Vector4f position = new Vector4f(positions.get(index[0]), 1);
Vec2 texCoord = index.length >= 2 && !texCoords.isEmpty() ? texCoords.get(index[1]) : DEFAULT_COORDS[i];
Vector3f norm0 = !needsNormalRecalculation && index.length >= 3 && !normals.isEmpty() ? normals.get(index[2]) : faceNormal;
Vector3f normal = norm0;
Vector4f color = index.length >= 4 && !colors.isEmpty() ? colors.get(index[3]) : COLOR_WHITE;
if (hasTransform)
{
if (hasTransform) {
normal = new Vector3f(norm0);
transformation.transformPosition(position);
transformation.transformNormal(normal);
@@ -430,16 +356,13 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
quadBaker.setUv2(uv2 & 0xFFFF, uv2 >> 16 & 0xFFFF);
quadBaker.setNormal(normal.x(), normal.y(), normal.z());
if (i == 0)
{
quadBaker.setDirection(Direction.getApproximateNearest(normal.x(), normal.y(), normal.z()));
}
pos[i] = position;
norm[i] = normal;
}
Direction cull = null;
if (automaticCulling)
{
if (automaticCulling) {
if (Mth.equal(pos[0].x(), 0) && // vertex.position.x
Mth.equal(pos[1].x(), 0) &&
Mth.equal(pos[2].x(), 0) &&
@@ -493,143 +416,123 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
return Pair.of(quadBaker.build(), cull);
}
public CompositeRenderable bakeRenderable(IGeometryBakingContext configuration)
{
public CompositeRenderable bakeRenderable(TextureSlots textures) {
var builder = CompositeRenderable.builder();
for (var entry : parts.entrySet())
{
for (var entry : parts.entrySet()) {
var name = entry.getKey();
var part = entry.getValue();
part.bake(builder.child(name), configuration);
part.bake(builder.child(name), textures);
}
return builder.get();
}
public class ModelObject
{
private class ModelObject {
public final String name;
List<ModelMesh> meshes = Lists.newArrayList();
ModelObject(String name)
{
ModelObject(String name) {
this.name = name;
}
public String name()
{
public String name() {
return name;
}
public void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ResourceLocation modelLocation)
{
for (ModelMesh mesh : meshes)
{
mesh.addQuads(owner, modelBuilder, spriteGetter, modelTransform);
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelTransform, ResourceLocation modelLocation) {
for (var mesh : meshes)
mesh.addQuads(owner, modelBuilder, baker, textures, modelTransform, modelLocation);
}
protected void bake(CompositeRenderable.PartBuilder<?> builder, TextureSlots textures) {
for (var mesh : this.meshes)
mesh.bake(builder, textures);
}
protected Collection<Material> getTextures(IGeometryBakingContext owner, TextureSlots textures, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors) {
var ret = new HashSet<Material>();
for (var mesh : meshes) {
if (mesh.mat != null)
ret.add(UnbakedGeometryHelper.resolveDirtyMaterial(mesh.mat.diffuseColorMap, textures));
}
return ret;
}
public void bake(CompositeRenderable.PartBuilder<?> builder, IGeometryBakingContext configuration)
{
for (ModelMesh mesh : this.meshes)
{
mesh.bake(builder, configuration);
}
}
public Collection<Material> getTextures(IGeometryBakingContext owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors)
{
return meshes.stream()
.flatMap(mesh -> mesh.mat != null
? Stream.of(UnbakedGeometryHelper.resolveDirtyMaterial(mesh.mat.diffuseColorMap, owner))
: Stream.of())
.collect(Collectors.toSet());
}
protected void addNamesRecursively(Set<String> names)
{
protected void addNamesRecursively(Set<String> names) {
names.add(name());
}
}
public class ModelGroup extends ModelObject
{
private class ModelGroup extends ModelObject {
final Map<String, ModelObject> parts = Maps.newLinkedHashMap();
ModelGroup(String name)
{
ModelGroup(String name) {
super(name);
}
@Override
public void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ResourceLocation modelLocation)
{
public void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) {
super.addQuads(owner, modelBuilder, baker, spriteGetter, modelTransform, modelLocation);
parts.values().stream().filter(part -> owner.isComponentVisible(part.name(), true))
.forEach(part -> part.addQuads(owner, modelBuilder, baker, spriteGetter, modelTransform, modelLocation));
}
@Override
public void bake(CompositeRenderable.PartBuilder<?> builder, IGeometryBakingContext configuration)
{
super.bake(builder, configuration);
for (var entry : parts.entrySet())
{
var name = entry.getKey();
var part = entry.getValue();
part.bake(builder.child(name), configuration);
for (var part : parts.values()) {
if (owner.isComponentVisible(part.name(), true))
part.addQuads(owner, modelBuilder, baker, spriteGetter, modelTransform, modelLocation);
}
}
@Override
public Collection<Material> getTextures(IGeometryBakingContext owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors)
{
public void bake(CompositeRenderable.PartBuilder<?> builder, TextureSlots textures) {
super.bake(builder, textures);
for (var entry : parts.entrySet()) {
var name = entry.getKey();
var part = entry.getValue();
part.bake(builder.child(name), textures);
}
}
@Override
public Collection<Material> getTextures(IGeometryBakingContext owner, TextureSlots textures, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors) {
Set<Material> combined = Sets.newHashSet();
combined.addAll(super.getTextures(owner, modelGetter, missingTextureErrors));
combined.addAll(super.getTextures(owner, textures, missingTextureErrors));
for (ModelObject part : parts.values())
combined.addAll(part.getTextures(owner, modelGetter, missingTextureErrors));
combined.addAll(part.getTextures(owner, textures, missingTextureErrors));
return combined;
}
@Override
protected void addNamesRecursively(Set<String> names)
{
protected void addNamesRecursively(Set<String> names) {
super.addNamesRecursively(names);
for (ModelObject object : parts.values())
object.addNamesRecursively(names);
}
}
private class ModelMesh
{
private class ModelMesh {
@Nullable
public ObjMaterialLibrary.Material mat;
@Nullable
public String smoothingGroup;
public final List<int[][]> faces = Lists.newArrayList();
public ModelMesh(@Nullable ObjMaterialLibrary.Material currentMat, @Nullable String currentSmoothingGroup)
{
public ModelMesh(@Nullable ObjMaterialLibrary.Material currentMat, @Nullable String currentSmoothingGroup) {
this.mat = currentMat;
this.smoothingGroup = currentSmoothingGroup;
}
public void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform)
{
protected void addQuads(IGeometryBakingContext owner, IModelBuilder<?> modelBuilder, ModelBaker baker, TextureSlots textures, ModelState modelTransform, ResourceLocation modelLocation) {
if (mat == null)
return;
TextureAtlasSprite texture = spriteGetter.apply(UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, owner));
var material = UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, textures);
var texture = baker.sprites().get(material);
int tintIndex = mat.diffuseTintIndex;
Vector4f colorTint = mat.diffuseColor;
var rootTransform = owner.getRootTransform();
var transform = rootTransform.isIdentity() ? modelTransform.getRotation() : modelTransform.getRotation().compose(rootTransform);
for (int[][] face : faces)
{
for (int[][] face : faces) {
Pair<BakedQuad, Direction> quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, texture, transform);
if (quad.getRight() == null)
modelBuilder.addUnculledFace(quad.getLeft());
@@ -638,8 +541,7 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
}
}
public void bake(CompositeRenderable.PartBuilder<?> builder, IGeometryBakingContext configuration)
{
public void bake(CompositeRenderable.PartBuilder<?> builder, TextureSlots textures) {
ObjMaterialLibrary.Material mat = this.mat;
if (mat == null)
return;
@@ -648,13 +550,12 @@ public class ObjModel extends SimpleUnbakedGeometry<ObjModel>
final List<BakedQuad> quads = new ArrayList<>();
for (var face : this.faces)
{
for (var face : this.faces) {
var pair = makeQuad(face, tintIndex, colorTint, mat.ambientColor, UnitTextureAtlasSprite.INSTANCE, Transformation.identity());
quads.add(pair.getLeft());
}
ResourceLocation textureLocation = UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, configuration).texture();
ResourceLocation textureLocation = UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, textures).texture();
ResourceLocation texturePath = textureLocation.withPath(p -> "textures/" + p + ".png");
builder.addMesh(texturePath, quads);
@@ -9,13 +9,12 @@ import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.util.Unit;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
import org.jetbrains.annotations.Nullable;
@@ -57,7 +56,7 @@ public class BakedModelRenderable implements IRenderable<BakedModelRenderable.Co
@Override
public void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay, float partialTick, Context context) {
var buffer = bufferSource.getBuffer(textureRenderTypeLookup.get(InventoryMenu.BLOCK_ATLAS));
var buffer = bufferSource.getBuffer(textureRenderTypeLookup.get(TextureAtlas.LOCATION_BLOCKS));
var tint = context.tint();
var randomSource = context.randomSource();
for (var direction : context.faces()) {
@@ -15,8 +15,7 @@ import net.minecraft.util.Unit;
* @param <T> The type of context object used by the rendering logic
*/
@FunctionalInterface
public interface IRenderable<T>
{
public interface IRenderable<T> {
/**
* Draws the renderable by adding the geometry to the provided {@link MultiBufferSource}
*
@@ -37,8 +36,7 @@ public interface IRenderable<T>
* @param context The context used for rendering
* @return A renderable that accepts {@link Unit#INSTANCE} as context, but uses the provided {@code context} instead
*/
default IRenderable<Unit> withContext(T context)
{
default IRenderable<Unit> withContext(T context) {
return (poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, unused) ->
this.render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, context);
}
@@ -6,17 +6,14 @@
package net.minecraftforge.client.textures;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.metadata.MetadataSectionSerializer;
import net.minecraft.server.packs.metadata.MetadataSectionType;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.util.GsonHelper;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Optional;
/**
* The "forge" section of texture metadata files (.mcmeta). Currently used only to specify custom
@@ -25,44 +22,26 @@ import java.util.Optional;
* @see ITextureAtlasSpriteLoader
*/
public record ForgeTextureMetadata(@Nullable ITextureAtlasSpriteLoader loader) {
public static final ForgeTextureMetadata EMPTY = new ForgeTextureMetadata(null);
public static final MetadataSectionSerializer<ForgeTextureMetadata> SERIALIZER = new Serializer();
private static final Codec<ITextureAtlasSpriteLoader> LOADER_CODEC = Codec.<ITextureAtlasSpriteLoader>stringResolver(
loader -> {
var ret = TextureAtlasSpriteLoaderManager.getKey(loader);
return ret == null ? null : ret.toString();
},
name -> TextureAtlasSpriteLoaderManager.get(ResourceLocation.parse(name))
);
private static final Codec<ForgeTextureMetadata> CODEC = RecordCodecBuilder.create(i ->
i.group(
LOADER_CODEC.fieldOf("loader").forGetter(ForgeTextureMetadata::loader)
).apply(i, ForgeTextureMetadata::new)
);
public static final MetadataSectionType<ForgeTextureMetadata> TYPE = new MetadataSectionType<>("forge", CODEC);
public static ForgeTextureMetadata forResource(Resource resource) throws IOException {
Optional<ForgeTextureMetadata> metadata = resource.metadata().getSection(SERIALIZER);
return metadata.orElse(EMPTY);
return resource.metadata().getSection(TYPE).orElse(EMPTY);
}
@Nullable
public ITextureAtlasSpriteLoader getLoader() {
return loader;
}
private static final class Serializer implements MetadataSectionSerializer<ForgeTextureMetadata> {
@Override
@NotNull
public String getMetadataSectionName() {
return "forge";
}
@Override
@NotNull
public ForgeTextureMetadata fromJson(JsonObject json) {
@Nullable
ITextureAtlasSpriteLoader loader;
if (json.has("loader")) {
ResourceLocation loaderName = ResourceLocation.parse(GsonHelper.getAsString(json, "loader"));
loader = TextureAtlasSpriteLoaderManager.get(loaderName);
if (loader == null) {
throw new JsonSyntaxException("Unknown TextureAtlasSpriteLoader " + loaderName);
}
} else {
loader = null;
}
return new ForgeTextureMetadata(loader);
}
}
}
@@ -5,23 +5,23 @@
package net.minecraftforge.client.textures;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.event.RegisterTextureAtlasSpriteLoadersEvent;
import net.minecraftforge.fml.ModLoader;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* Manager for {@link ITextureAtlasSpriteLoader} instances.
* <p>
* Provides a lookup.
* TODO: Convert this into a proper registry
*/
public final class TextureAtlasSpriteLoaderManager {
private static Map<ResourceLocation, ITextureAtlasSpriteLoader> LOADERS;
private static BiMap<ResourceLocation, ITextureAtlasSpriteLoader> LOADERS;
/**
* Finds the loader with the given name, or null if none is registered.
@@ -31,12 +31,17 @@ public final class TextureAtlasSpriteLoaderManager {
return LOADERS.get(name);
}
@Nullable
public static ResourceLocation getKey(ITextureAtlasSpriteLoader value) {
return LOADERS.inverse().get(value);
}
@ApiStatus.Internal
public static void init() {
var loaders = new HashMap<ResourceLocation, ITextureAtlasSpriteLoader>();
var loaders = HashBiMap.<ResourceLocation, ITextureAtlasSpriteLoader>create();
var event = new RegisterTextureAtlasSpriteLoadersEvent(loaders);
ModLoader.get().postEventWrapContainerInModOrder(event);
LOADERS = ImmutableMap.copyOf(loaders);
LOADERS = ImmutableBiMap.copyOf(loaders);
}
private TextureAtlasSpriteLoaderManager() {}
@@ -685,7 +685,7 @@ public final class ForgeHooks {
if (potion != null && potion.unwrapKey().isPresent())
return potion.unwrapKey().get().location().getNamespace();
} else if (item instanceof SpawnEggItem egg) {
var resourceLocation = ForgeRegistries.ENTITY_TYPES.getKey(egg.getType(itemStack));
var resourceLocation = EntityType.getKey(egg.getDefaultType());
if (resourceLocation != null)
return resourceLocation.getNamespace();
}
@@ -1,106 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DispenseItemBehavior;
import net.minecraft.util.ARGB;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class ForgeSpawnEggItem extends SpawnEggItem {
private static final List<ForgeSpawnEggItem> MOD_EGGS = new ArrayList<>();
private static final Map<EntityType<? extends Mob>, ForgeSpawnEggItem> TYPE_MAP = new IdentityHashMap<>();
private final Supplier<? extends EntityType<? extends Mob>> typeSupplier;
@SuppressWarnings("deprecation")
public ForgeSpawnEggItem(Supplier<? extends EntityType<? extends Mob>> type, int backgroundColor, int highlightColor, Properties props) {
super((EntityType<? extends Mob>)null, backgroundColor, highlightColor, props);
this.typeSupplier = type;
MOD_EGGS.add(this);
}
@Nullable
protected DispenseItemBehavior createDispenseBehavior() {
return DEFAULT_DISPENSE_BEHAVIOR;
}
@SuppressWarnings("deprecation")
@Nullable
public static SpawnEggItem fromEntityType(@Nullable EntityType<?> type) {
SpawnEggItem ret = TYPE_MAP.get(type);
return ret != null ? ret : SpawnEggItem.byId(type);
}
@Override
protected EntityType<?> getDefaultType() {
return this.typeSupplier.get();
}
private static final DispenseItemBehavior DEFAULT_DISPENSE_BEHAVIOR = (source, stack) -> {
Direction face = source.state().getValue(DispenserBlock.FACING);
EntityType<?> type = ((SpawnEggItem)stack.getItem()).getType(stack);
try {
type.spawn(source.level(), stack, null, source.pos().relative(face), EntitySpawnReason.DISPENSER, face != Direction.UP, false);
} catch (Exception exception) {
DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), exception);
return ItemStack.EMPTY;
}
stack.shrink(1);
source.level().gameEvent(GameEvent.ENTITY_PLACE, source.pos(), GameEvent.Context.of(source.state()));
return stack;
};
@Mod.EventBusSubscriber(modid = "forge", bus = Mod.EventBusSubscriber.Bus.MOD)
private static class CommonHandler {
@SubscribeEvent
public static void onCommonSetup(FMLCommonSetupEvent event) {
MOD_EGGS.forEach(egg -> {
DispenseItemBehavior dispenseBehavior = egg.createDispenseBehavior();
if (dispenseBehavior != null)
DispenserBlock.registerBehavior(egg, dispenseBehavior);
TYPE_MAP.put(egg.typeSupplier.get(), egg);
});
}
}
@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = "forge", bus = Mod.EventBusSubscriber.Bus.MOD)
private static class ColorRegisterHandler {
@SubscribeEvent(priority = EventPriority.HIGHEST)
public static void registerSpawnEggColors(RegisterColorHandlersEvent.Item event) {
for (ForgeSpawnEggItem egg : MOD_EGGS) {
event.register((stack, layer) -> {
int color = egg.getColor(layer);
if (ARGB.alpha(color) == 0)
color = ARGB.opaque(color);
return color;
}, egg);
}
}
}
}
@@ -10,6 +10,7 @@ import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.Holder;
import net.minecraft.resources.DelegatingOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraftforge.registries.ForgeRegistries;
@@ -36,6 +37,10 @@ public interface ICondition {
@ApiStatus.Internal
public static ResourceLocation KEY = ResourceLocation.fromNamespaceAndPath("forge", "condition_context");
default <T, O extends DelegatingOps<T>> O wrap(O ops) {
return ops.withContext(KEY, this);
}
IContext EMPTY = new IContext() {
@Override
public <T> Collection<Holder<T>> getTag(TagKey<T> key) {
@@ -5,6 +5,7 @@
package net.minecraftforge.common.crafting.ingredients;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
@@ -32,6 +33,15 @@ public abstract class AbstractIngredient extends Ingredient {
@Override
public abstract IIngredientSerializer<? extends Ingredient> serializer();
@Override
public boolean isEmpty() {
return this.items().count() == 0;
}
@Override
public boolean acceptsItem(Holder<Item> item) {
return this.items().anyMatch(i -> i.equals(item));
}
/* Hide vanilla ingredient static constructors to reduce errors with constructing custom ingredients */
@@ -9,6 +9,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@@ -44,14 +46,14 @@ public class CompoundIngredient extends AbstractIngredient {
@Override
@NotNull
public List<Holder<Item>> items() {
public Stream<Holder<Item>> items() {
if (this.items == null) {
var tmp = new ArrayList<Holder<Item>>();
for (var child : children)
tmp.addAll(child.items());
child.items().forEach(tmp::add);
this.items = Collections.unmodifiableList(tmp);
}
return this.items;
return this.items.stream();
}
@Override
@@ -18,6 +18,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/** Ingredient that matches everything from the first ingredient that is not included in the second ingredient */
public class DifferenceIngredient extends AbstractIngredient {
@@ -49,24 +50,18 @@ public class DifferenceIngredient extends AbstractIngredient {
@SuppressWarnings("deprecation")
@Override
public List<Holder<Item>> items() {
public Stream<Holder<Item>> items() {
if (this.items == null) {
var tmp = new ArrayList<Holder<Item>>();
for (var base : this.base.items()) {
boolean match = false;
for (var item : this.subtracted.items()) {
if (base.is(item)) {
match = true;
break;
}
}
this.base.items().forEach(base -> {
boolean match = this.subtracted.items().anyMatch(base::is);
if (!match)
tmp.add(base);
}
});
this.items = Collections.unmodifiableList(tmp);
}
return items;
return items.stream();
}
@Override
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/** Ingredient that matches if all child ingredients match */
public class IntersectionIngredient extends AbstractIngredient {
@@ -61,20 +62,14 @@ public class IntersectionIngredient extends AbstractIngredient {
@SuppressWarnings("deprecation")
@Override
public List<Holder<Item>> items() {
public Stream<Holder<Item>> items() {
if (this.items == null) {
var tmp = new ArrayList<Holder<Item>>();
for (var base : children.get(0).items()) {
children.get(0).items().forEach(base -> {
boolean allMatch = true;
for (int i = 1; i < children.size(); i++) {
boolean match = false;
for (var item : children.get(i).items()) {
if (base.is(item)) {
match = true;
break;
}
}
boolean match = children.get(i).items().anyMatch(base::is);
if (!match) {
allMatch = false;
break;
@@ -82,10 +77,10 @@ public class IntersectionIngredient extends AbstractIngredient {
}
if (allMatch)
tmp.add(base);
}
});
this.items = Collections.unmodifiableList(tmp);
}
return items;
return items.stream();
}
@Override
@@ -36,7 +36,6 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.server.level.ServerLevel;
import net.minecraftforge.client.ForgeHooksClient;
@@ -271,17 +270,6 @@ public interface IForgeBlock {
return self().getExplosionResistance();
}
/**
*
* Called when A user uses the creative pick block button on this block
*
* @param target The full target the player is looking at
* @return A ItemStack to add to the player's inventory, empty itemstack if nothing should be added.
*/
default ItemStack getCloneItemStack(BlockState state, HitResult target, LevelReader level, BlockPos pos, Player player) {
return self().getCloneItemStack(level, pos, state);
}
/**
* Allows a block to override the standard EntityLivingBase.updateFallState
* particles, this is a server side method that spawns particles with
@@ -5,7 +5,6 @@
package net.minecraftforge.common.extensions;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
@@ -22,10 +22,8 @@ import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.server.level.ServerLevel;
import net.minecraftforge.common.IPlantable;
@@ -200,17 +198,6 @@ public interface IForgeBlockState {
return self().getBlock().getExplosionResistance(self(), level, pos, explosion);
}
/**
*
* Called when A user uses the creative pick block button on this block
*
* @param target The full target the player is looking at
* @return A ItemStack to add to the player's inventory, empty itemstack if nothing should be added.
*/
default ItemStack getCloneItemStack(HitResult target, LevelReader level, BlockPos pos, Player player) {
return self().getBlock().getCloneItemStack(self(), target, level, pos, player);
}
/**
* Allows a block to override the standard EntityLivingBase.updateFallState
* particles, this is a server side method that spawns particles with
@@ -17,14 +17,11 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.ForgeSpawnEggItem;
import net.minecraftforge.common.SoundAction;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.entity.PartEntity;
@@ -72,21 +69,6 @@ public interface IForgeEntity extends ICapabilitySerializable<CompoundTag> {
return true;
}
/**
* Called when a user uses the creative pick block button on this entity.
*
* @param target The full target the player is looking at
* @return A ItemStack to add to the player's inventory, empty ItemStack if nothing should be added.
*/
default ItemStack getPickedResult(HitResult target) {
var result = self().getPickResult();
if (result == null) {
var egg = ForgeSpawnEggItem.fromEntityType(self().getType());
result = egg == null ? ItemStack.EMPTY : new ItemStack(egg);
}
return result;
}
/**
* If a rider of this entity can interact with this entity. Should return true on the
* ridden entity if so.
@@ -25,6 +25,7 @@ import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.GsonHelper;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.ResourceLocation;
public class LootModifierManager extends SimpleJsonResourceReloadListener<JsonElement> {
@@ -36,7 +37,7 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener<JsonEl
private Map<ResourceLocation, IGlobalLootModifier> modifiers = ImmutableMap.of();
public LootModifierManager(HolderLookup.Provider registries) {
super(registries, ExtraCodecs.JSON, FOLDER);
super(registries.createSerializationContext(JsonOps.INSTANCE), ExtraCodecs.JSON, FileToIdConverter.json(FOLDER));
this.registries = registries;
}
@@ -10,6 +10,7 @@ import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.sounds.Music;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.level.biome.AmbientAdditionsSettings;
import net.minecraft.world.level.biome.AmbientMoodSettings;
import net.minecraft.world.level.biome.AmbientParticleSettings;
@@ -19,10 +20,8 @@ import net.minecraft.world.level.biome.BiomeSpecialEffects;
* Extension of the vanilla builder but also provides read access and a copy-from-existing-data helper.
* Also, the base builder crashes if certain values aren't specified on build, so this enforces the setting of those.
*/
public class BiomeSpecialEffectsBuilder extends BiomeSpecialEffects.Builder
{
public static BiomeSpecialEffectsBuilder copyOf(BiomeSpecialEffects baseEffects)
{
public class BiomeSpecialEffectsBuilder extends BiomeSpecialEffects.Builder {
public static BiomeSpecialEffectsBuilder copyOf(BiomeSpecialEffects baseEffects) {
BiomeSpecialEffectsBuilder builder = BiomeSpecialEffectsBuilder.create(baseEffects.getFogColor(), baseEffects.getWaterColor(), baseEffects.getWaterFogColor(), baseEffects.getSkyColor());
builder.grassColorModifier = baseEffects.getGrassColorModifier();
baseEffects.getFoliageColorOverride().ifPresent(builder::foliageColorOverride);
@@ -35,13 +34,11 @@ public class BiomeSpecialEffectsBuilder extends BiomeSpecialEffects.Builder
return builder;
}
public static BiomeSpecialEffectsBuilder create(int fogColor, int waterColor, int waterFogColor, int skyColor)
{
public static BiomeSpecialEffectsBuilder create(int fogColor, int waterColor, int waterFogColor, int skyColor) {
return new BiomeSpecialEffectsBuilder(fogColor, waterColor, waterFogColor, skyColor);
}
protected BiomeSpecialEffectsBuilder(int fogColor, int waterColor, int waterFogColor, int skyColor)
{
protected BiomeSpecialEffectsBuilder(int fogColor, int waterColor, int waterFogColor, int skyColor) {
super();
this.fogColor(fogColor);
this.waterColor(waterColor);
@@ -49,63 +46,51 @@ public class BiomeSpecialEffectsBuilder extends BiomeSpecialEffects.Builder
this.skyColor(skyColor);
}
public int getFogColor()
{
public int getFogColor() {
return this.fogColor.getAsInt();
}
public int waterColor()
{
public int waterColor() {
return this.waterColor.getAsInt();
}
public int getWaterFogColor()
{
public int getWaterFogColor() {
return this.waterFogColor.getAsInt();
}
public int getSkyColor()
{
public int getSkyColor() {
return this.skyColor.getAsInt();
}
public BiomeSpecialEffects.GrassColorModifier getGrassColorModifier()
{
public BiomeSpecialEffects.GrassColorModifier getGrassColorModifier() {
return this.grassColorModifier;
}
public Optional<Integer> getFoliageColorOverride()
{
public Optional<Integer> getFoliageColorOverride() {
return this.foliageColorOverride;
}
public Optional<Integer> getGrassColorOverride()
{
public Optional<Integer> getGrassColorOverride() {
return this.grassColorOverride;
}
public Optional<AmbientParticleSettings> getAmbientParticle()
{
public Optional<AmbientParticleSettings> getAmbientParticle() {
return this.ambientParticle;
}
public Optional<Holder<SoundEvent>> getAmbientLoopSound()
{
public Optional<Holder<SoundEvent>> getAmbientLoopSound() {
return this.ambientLoopSoundEvent;
}
public Optional<AmbientMoodSettings> getAmbientMoodSound()
{
public Optional<AmbientMoodSettings> getAmbientMoodSound() {
return this.ambientMoodSettings;
}
public Optional<AmbientAdditionsSettings> getAmbientAdditionsSound()
{
public Optional<AmbientAdditionsSettings> getAmbientAdditionsSound() {
return this.ambientAdditionsSettings;
}
public Optional<Music> getBackgroundMusic()
{
public Optional<SimpleWeightedRandomList<Music>> getBackgroundMusic() {
return this.backgroundMusic;
}
}
@@ -18,12 +18,17 @@ import org.apache.logging.log4j.Logger;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
public class DatagenModLoader {
private static final Logger LOGGER = LogManager.getLogger();
private static ExistingFileHelper existingFileHelper;
@@ -33,13 +38,49 @@ public class DatagenModLoader {
return runningDataGen;
}
public static void begin(
Set<String> patterns, Path output, Collection<Path> inputs, Collection<Path> existingPacks, Set<String> existingMods,
boolean genServer, boolean genClient, boolean genDev, boolean genReports,
boolean validate, boolean flat, String assetIndex, File assetsDir
public static DatagenModLoader setup(OptionParser parser, boolean client) {
return new DatagenModLoader(parser, client);
}
private final OptionParser parser;
private final boolean client;
private final OptionSpec<String> existing;
private final OptionSpec<String> existingMod;
private final OptionSpec<String> mod;
private final OptionSpec<String> assetIndex;
private final OptionSpec<File> gameDir;
private final OptionSpec<File> assetsDir;
private final OptionSpec<Void> flat;
private DatagenModLoader(OptionParser parser, boolean client) {
this.gameDir = parser.accepts("gameDir").withRequiredArg().ofType(java.io.File.class).defaultsTo(new java.io.File(".")).required(); //Need by modlauncher, so lets just eat it
this.parser = parser;
this.client = client;
this.existing = parser.accepts("existing", "Existing resource packs that generated resources can reference").withRequiredArg();
this.existingMod = parser.accepts("existing-mod", "Existing mods that generated resources can reference the resource packs of").withRequiredArg();
this.mod = parser.accepts("mod", "A modid to dump").withRequiredArg().withValuesSeparatedBy(",");
this.flat = parser.accepts("flat", "Do not append modid prefix to output directory when generating for multiple mods");
this.assetIndex = parser.accepts("assetIndex").withRequiredArg();
this.assetsDir = parser.accepts("assetsDir").withRequiredArg().ofType(java.io.File.class);
}
public boolean hasArgs(OptionSet options) {
return options.specs().size() != 1 || !options.has(gameDir);
}
public boolean run(
OptionSet options, Path output, Collection<Path> inputs,
boolean genServer, boolean genClient, boolean genDev, boolean genReports, boolean validate
) {
var existingPacks = options.valuesOf(this.existing).stream().map(Paths::get).toList();
var existingMods = new HashSet<>(options.valuesOf(this.existingMod));
var patterns = new HashSet<>(options.valuesOf(this.mod));
var flat = patterns.isEmpty() || options.has(this.flat);
var assetIndex = options.valueOf(this.assetIndex);
var assetsDir = options.valueOf(this.assetsDir);
if (patterns.contains("minecraft") && patterns.size() == 1)
return;
return true;
runningDataGen = true;
Bootstrap.bootStrap();
@@ -77,5 +118,7 @@ public class DatagenModLoader {
), config, existingFileHelper)
);
config.runAll();
return false;
}
}
@@ -21,7 +21,7 @@ import net.minecraft.server.packs.AbstractPackResources;
import net.minecraft.server.packs.PackLocationInfo;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.metadata.MetadataSectionSerializer;
import net.minecraft.server.packs.metadata.MetadataSectionType;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.Pack.Metadata;
@@ -58,8 +58,8 @@ public class DelegatingPackResources extends AbstractPackResources {
@SuppressWarnings("unchecked")
@Nullable
@Override
public <T> T getMetadataSection(MetadataSectionSerializer<T> deserializer) throws IOException {
return deserializer.getMetadataSectionName().equals("pack") ? (T) this.packMeta : null;
public <T> T getMetadataSection(MetadataSectionType<T> deserializer) throws IOException {
return deserializer.name().equals("pack") ? (T) this.packMeta : null;
}
@Override