Jump to content

Recommended Posts

Posted (edited)

Hey guys!

I created a block (slab, to be axact), that takes on the texture of the block it is clicked on. For that I used Baked Models. Now nearly everything works fine, but the slab texture (when covered by a block) is way too dark (see attached pictures), as if the light level was zero. As you can see in the first picture, it works well for the json-block-model, when the slab does not contain any block (oak planks texture). So I guess the problem is somewhere in the baked model, but I can't figure it out.

Here's the code for my BakedModel-Class extending IDynamicBakedModel:

getQuads (Overrides interface method)

public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) {
        //get block saved in slab's tile entity
        BlockState mimic = extraData.getData(FrameBlockTile.MIMIC);
        //check if not empty
        if (mimic != null && !(mimic.getBlock() instanceof FrameBlock)) {
            //location of BlockModel
            ModelResourceLocation location = BlockModelShapes.getModelLocation(mimic);
            if (location != null) {
                IBakedModel model = Minecraft.getInstance().getModelManager().getModel(location);
                model.getBakedModel().getQuads(mimic, side, rand, extraData);
                if (model != null) {
                    //new quad-model with data from slab
                    return getMimicQuads(mimic, side, rand, extraData);
                }
            }
        }
        return Collections.emptyList();

the called method "getMimicQuads":

public List<BakedQuad> getMimicQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) {
        if (side != null) {
            return Collections.emptyList();
        }
        BlockState mimic = extraData.getData(FrameBlockTile.MIMIC);
        if (mimic!=null) {
          	//get texture from block saved in slab
            TextureAtlasSprite texture = Minecraft.getInstance().getAtlasSpriteGetter(AtlasTexture.LOCATION_BLOCKS_TEXTURE).apply(new ResourceLocation(mimic.getBlock().getRegistryName().getNamespace(), "block/"+mimic.getBlock().getRegistryName().getPath()));
            List<BakedQuad> quads = new ArrayList<>();
          	//create 6 faces of slab
            //down
            quads.add(createQuad(v(1, 0, 0), v(1, 0, 1), v(0, 0, 1), v(0, 0, 0), texture));
            //up
            quads.add(createQuad(v(0, 0.5, 0), v(0, 0.5, 1), v(1, 0.5, 1), v(1, 0.5, 0), texture));
            //sides
            quads.add(createHalfQuad(v(0, 0, 0), v(0, 0, 1), v(0, 0.5, 1), v(0, 0.5, 0), texture));
            quads.add(createHalfQuad(v(0, 0, 0), v(0, 0.5, 0), v(1, 0.5, 0), v(1, 0, 0), texture));
            quads.add(createHalfQuad(v(0, 0, 1), v(1, 0, 1), v(1, 0.5, 1), v(0, 0.5, 1), texture));
            quads.add(createHalfQuad(v(1, 0.5, 0), v(1, 0.5, 1), v(1, 0, 1), v(1, 0, 0), texture));

            return quads;
        }
        return Collections.emptyList();
    }

the called createQuad and createHalfQuad methods:

	//for squared part of slab (top and bottom side)
	private BakedQuad createQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, TextureAtlasSprite sprite) {
        Vec3d normal = v3.subtract(v2).crossProduct(v1.subtract(v2)).normalize();

        BakedQuadBuilder builder = new BakedQuadBuilder(sprite);
        builder.setQuadOrientation(Direction.getFacingFromVector(normal.x, normal.y, normal.z));
        putVertex(builder, normal, v1.x, v1.y, v1.z, 0, 0, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v2.x, v2.y, v2.z, 0, 16, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v3.x, v3.y, v3.z, 16, 16, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v4.x, v4.y, v4.z, 16, 0, sprite, 1.0f, 1.0f, 1.0f);
        return builder.build();
    }
	//for rectangles (sides of slab)
	private BakedQuad createHalfQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, TextureAtlasSprite sprite) {
        Vec3d normal = v3.subtract(v2).crossProduct(v1.subtract(v2)).normalize();

        BakedQuadBuilder builder = new BakedQuadBuilder(sprite);
        builder.setQuadOrientation(Direction.getFacingFromVector(normal.x, normal.y, normal.z));
        putVertex(builder, normal, v1.x, v1.y, v1.z, 0, 0, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v2.x, v2.y, v2.z, 0, 8, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v3.x, v3.y, v3.z, 16, 8, sprite, 1.0f, 1.0f, 1.0f);
        putVertex(builder, normal, v4.x, v4.y, v4.z, 16, 0, sprite, 1.0f, 1.0f, 1.0f);
        return builder.build();
    }

and the putVertex-method for creating the vertices:

private void putVertex(BakedQuadBuilder builder, Vec3d normal,
                           double x, double y, double z, float u, float v, TextureAtlasSprite sprite, float r, float g, float b) {

        ImmutableList<VertexFormatElement> elements = builder.getVertexFormat().getElements().asList();
        for (int j = 0 ; j < elements.size() ; j++) {
            VertexFormatElement e = elements.get(j);
            switch (e.getUsage()) {
                case POSITION:
                    builder.put(j, (float) x, (float) y, (float) z, 1.0f);
                    break;
                case COLOR:
                    builder.put(j, r, g, b, 1.0f);
                    break;
                case UV:
                    switch (e.getIndex()) {
                        case 0:
                            float iu = sprite.getInterpolatedU(u);
                            float iv = sprite.getInterpolatedV(v);
                            builder.put(j, iu, iv);
                            break;
                        case 2:
                            builder.put(j, 0f, 1f);
                            break;
                        default:
                            builder.put(j);
                            break;
                    }
                    break;
                case NORMAL:
                    builder.put(j, (float) normal.x, (float) normal.y, (float) normal.z);
                    break;
                default:
                    builder.put(j);
                    break;
            }
        }
    }

 

Ambient Occlusion is set to true (I read, that this might be the reason, but when I toggled it multiple times nothing really changed)

Gui3d and BuildInRenderer both return false

 

As I said, the texture is too dark, like if the light level was zero and I want to fix that. I really don't know what to do anymore. Any help is appreciated. Thanks in advance

(I hope you understand, what I was trying to say, english is not my native language)

Kind Regards, Manu

2020-06-10_13.30.52.png

2020-06-10_13.30.55.png

Edited by PianoManu
Problem is solved. Thanks to you, TGG!
Posted

Howdy

I don't see you put any lightmap information into your vertex, but I presume you are using the Block vertex format?  In my previous digging through the rendering code, I sometime found that to be important.

 

DefaultVertexFormats.BLOCK

    // IVertexBuilder::addQuad and FaceBakery; see also DefaultVertexFormats.BLOCK.
    // Summary:
    //    faceData[i + 0] = Float.floatToRawIntBits(positionIn.getX());
    //    faceData[i + 1] = Float.floatToRawIntBits(positionIn.getY());
    //    faceData[i + 2] = Float.floatToRawIntBits(positionIn.getZ());
    //    faceData[i + 3] = shadeColor;
    //    faceData[i + 4] = Float.floatToRawIntBits(textureU));
    //    faceData[i + 5] = Float.floatToRawIntBits(textureV));
    //    faceData[i + 6] = baked lighting (blocklight + skylight)
    //    faceData[i + 7] = normal;

 

You could consider using the face bakery to generate your quads, like this

  /**
   * Returns a quad for the given digit
   * @param digit the digit (0 -> 9)
   * @param isBlank if true: this digit should be blank (is a leading zero)
   * @param minX: the minimum [x,y,z] of the digit quad (from the viewer's point of view).  units = model space i.e. 0->16 is 1 metre block
   * @param maxX: the maximum [x,y,z] of the digit quad (from the viewer's point of view).  units = model space i.e. 0->16 is 1 metre block
   * @return
   */
  private BakedQuad getQuadForDigit(int digit, boolean isBlank, Direction whichFace,
                                    double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
    // generate a BakedQuad for the given digit

    // we can do this manually by providing a list of vertex data, or we can use the FaceBakery::bakeQuads method
    // FaceBakery::bakeQuad is much simpler and suitable for pretty much any block-style rendering, so I've used that here
    // If you want to manually provide vertex data yourself, the format is an array of ints; look in
    // IVertexBuilder::addQuad and FaceBakery; see also DefaultVertexFormats.BLOCK.
    // Summary:
    //    faceData[i + 0] = Float.floatToRawIntBits(positionIn.getX());
    //    faceData[i + 1] = Float.floatToRawIntBits(positionIn.getY());
    //    faceData[i + 2] = Float.floatToRawIntBits(positionIn.getZ());
    //    faceData[i + 3] = shadeColor;
    //    faceData[i + 4] = Float.floatToRawIntBits(textureU));
    //    faceData[i + 5] = Float.floatToRawIntBits(textureV));
    //    faceData[i + 6] = baked lighting (blocklight + skylight)
    //    faceData[i + 7] = normal;
    // When constructing a face manually in this way, the order of vertices is very important!
    // 1) must be added anti-clockwise (from the point of view of the person looking at the face).  Otherwise the face
    //    will point in the wrong direction and it may be invisible (backs of faces are usually culled for block rendering)
    // 2) ambient occlusion (a block lighting effect) assumes that the vertices are added in the order:
    //     top left, then bottom left, then bottom right, then top right - for the east, west, north, south faces.
    //     for the top face: NW, SW, SE, NE.  for the bottom face: SW, NW, NE, SE
    //    If your face has ambient occlusion enabled, and the order is wrong, then the shading will be messed up

    // FaceBakery:
    //  Vanilla uses it to convert from the elements in a block model, i.e.
    //    "elements": [
    //    { "from": [ 7, 0, 7 ],
    //      "to": [ 9, 10, 9 ],
    //      "shade": false,
    //      "faces": {
    //        "down": { "uv": [ 7, 13, 9, 15 ], "texture": "#torch" },
    //        "up":   { "uv": [ 7,  6, 9,  8 ], "texture": "#torch" }
    //      }
    //    },
    //    see https://minecraft.gamepedia.com/Model#Block_models
    //  In order to use the FaceBakery::bakeQuad method, we need to provide:
    //   1) A suitable cuboid 'from' and 'to', in model coordinate (eg the full 1 metre cube is from [0,0,0] to [16, 16, 16])
    //   2) the corresponding [u,v] texture coordinates for the face: [minU,minV] first then [maxU,maxV], again in texels 0->16
    //   3) the face we want to make the quad for (eg up, down, east, west, etc).

    Vector3f from = new Vector3f((float)minX, (float)minY, (float)minZ);
    Vector3f to = new Vector3f((float)maxX, (float)maxY, (float)maxZ);

    // texture UV order is important! i.e. [minU,minV] first then [maxU,maxV]
    float [] uvArray = getDigitUVs(digit, isBlank);
    final int ROTATION_NONE = 0;
    BlockFaceUV blockFaceUV = new BlockFaceUV(uvArray, ROTATION_NONE);

    final Direction NO_FACE_CULLING = null;
    final int TINT_INDEX_NONE = -1;  // used for tintable blocks such as grass, which make a call to BlockColors to change their rendering colour.  -1 for not tintable.
    final String DUMMY_TEXTURE_NAME = "";  // texture name is only needed for loading from json files; not needed here
    BlockPartFace blockPartFace = new BlockPartFace(NO_FACE_CULLING, TINT_INDEX_NONE, DUMMY_TEXTURE_NAME,  blockFaceUV);

    // we have previously registered digitsTexture in StartupClientOnly::onTextureStitchEvent
    AtlasTexture blocksStitchedTextures = ModelLoader.instance().getSpriteMap().getAtlasTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE);
    TextureAtlasSprite digitsTextures = blocksStitchedTextures.getSprite(digitsTextureRL);

    final IModelTransform NO_TRANSFORMATION = IDENTITY;
    final BlockPartRotation DEFAULT_ROTATION = null;   // rotate based on the face direction
    final boolean APPLY_SHADING = true;
    final ResourceLocation DUMMY_RL = new ResourceLocation("dummy_name");  // used for error message only
    BakedQuad bakedQuad = faceBakery.bakeQuad(from, to, blockPartFace, digitsTextures, whichFace, NO_TRANSFORMATION, DEFAULT_ROTATION,
                             APPLY_SHADING, DUMMY_RL);
    return bakedQuad;
  }

 

If that doesn't help, I'd suggest you add a breakpoint to ForgeBlockModelRenderer::renderModelSmooth (or much easier - ::renderModelFlat if you turn off ambient occlusion) and watch how your block's quads are rendered to the buffer.

 

I've also had this problem arise previously with blocks which used the skylight+blocklight value for rendering but which had a calculated skylight+blocklight of 0 due to the block's settings (I forget which, sorry).   The breakpoint I suggested above should show that, if it's the cause.

 

-TGG

 

 

 

 

  • Like 1
Posted

Hey, thanks for your reply!

I've read your text several times and I'm beginning to understand, but I've never worked with the FaceBakery before, so I don't have any experiences with that. Do I have to rewrite the whole baked model class to extend the FaceBakery instead of implementing IDynamicBakedModel? I've looked through the FaceBakery class and the IVertexBuilder, but I have no clue where to begin with... Maybe you could give me a hint?

Or do I have to rewrite everything at all?

 

Also, where is this code part from? I couldn't find anything on Google, when I searched for "getQuadForDigit". I ask because maybe I could get some more information from the context of the code

 

Thank you for your help!

Posted
21 hours ago, TheGreyGhost said:

I don't see you put any lightmap information into your vertex

Sorry for bothering you again, but I've searched and tested a bit further and honestly I don't know how to put it into the vertex as I don't have any lightmap information (as far as I know) and both the BakedQuadBuilder and the VertexFormatElement do not take/contain any lighting information. How do you mean that? Like, what do I have to add?

Thanks for helping me!

Posted

Howdy

The code is from this example project

https://github.com/TheGreyGhost/MinecraftByExample

(mbe04 AltimeterBakedModel)

 

The definition for the vertex format of BLOCK is 

public static final VertexFormat BLOCK = new VertexFormat(ImmutableList.<VertexFormatElement>builder()
  .add(POSITION_3F)  //[x,y,z]
  .add(COLOR_4UB) // colour info
  .add(TEX_2F) // texture
  .add(TEX_2SB) // lighting (blocklight + skylight)
  .add(NORMAL_3B) // normal 
  .add(PADDING_1B).build());

but you're right, the lighting is often not used / is added during rendering.

 

If you put your code into a github I'll have a look in the next day or so to figure it out.  I think it's almost certainly a block setting or voxelshape problem that's causing the lightmap to be wrong, it won't take me long to confirm it.

 

Cheers

  TGG

 

 

 

  • Thanks 1
Posted (edited)
2 hours ago, TheGreyGhost said:

The code is from this example project

https://github.com/TheGreyGhost/MinecraftByExample

(mbe04 AltimeterBakedModel)

Thank you very much!

 

This is my git repository: https://github.com/PianoManu/BlockCarpentry

The registration of the block is located in the setup-package in the Registration class.

The model loaders are registered in the setup-package in the ClientSetup class - there are three model loaders, the "frameloader" loads the full block and works fine. The problematic one is the "frame_slab_bottom_loader".

The Baked Model for the slab is located in the bakedmodels package as "SlabFrameBottomBakedModel" class

 

Thank you very much for your help! I will be really happy if you find my mistake ?

Regards, Manu

 

Edit: for some weird reason, the "main" directory is outside of the "src" directory in the git repository and you can't open the src directory... But everything is contained in the main directory so I guess it's fine...

Edited by PianoManu
Posted

Howdy

 

The problem is here; you mixed up short (2 bytes long) and float(4 bytes long) so your UV was overwriting dud values into the baked skylight+blocklight.

 

    private void putVertex(BakedQuadBuilder builder, Vec3d normal,
                           double x, double y, double z, float u, float v, TextureAtlasSprite sprite, float r, float g, float b) {

        //ImmutableList<VertexFormatElement> elements = builder.getVertexFormat().getElements().asList();
        ImmutableList<VertexFormatElement> elements = SLAB_BLOCK.getElements().asList();
        for (int j = 0 ; j < elements.size() ; j++) {
            VertexFormatElement e = elements.get(j);
            switch (e.getUsage()) {
                case POSITION:
                    builder.put(j, (float) x, (float) y, (float) z, 1.0f);
                    break;
                case COLOR:
                    builder.put(j, r, g, b, 1.0f);
                    break;
                case UV:
                    switch (e.getIndex()) {
                        case 0:
                            float iu = sprite.getInterpolatedU(u);
                            float iv = sprite.getInterpolatedV(v);
                            builder.put(j, iu, iv);
                            break;
                        case 2:
                            builder.put(j, (short)0, (short)0);  // error is here
                            break;
                        default:
                            builder.put(j);
                            break;
                    }
                    break;
                case NORMAL:
                    builder.put(j, (float) normal.x, (float) normal.y, (float) normal.z);
                    break;
                default:
                    builder.put(j);
                    break;
            }
        }
        builder.setApplyDiffuseLighting(true);
    }

 

Due to non-defensive coding assumptions in IForgeVertexBuilder, it was taking your incorrect slBaked value (2047 instead of 0), overwriting the skylight (15), leaving a packed texture coordinate with zeros in the least significant bits, i.e. effectively 0 skylight = dark.

    default int applyBakedLighting(int lightmapCoord, ByteBuffer data) {
        int bl = LightTexture.getLightBlock(lightmapCoord);
        int sl = LightTexture.getLightSky(lightmapCoord);
        int offset = LightUtil.getLightOffset(0) * 4; // int offset for vertex 0 * 4 bytes per int
        int blBaked = Short.toUnsignedInt(data.getShort(offset)) >> 4;
        int slBaked = Short.toUnsignedInt(data.getShort(offset + 2)) >> 4;
        bl = Math.max(bl, blBaked);
        sl = Math.max(sl, slBaked);
        return LightTexture.packLight(bl, sl);
    }

 

It works fine now...

 

-TGG

 

2020-06-13_13_43_31.png.22d1a6e1f7845bd661978507894c5193.png

  • Thanks 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Cracked Launchers are not supported
    • After some time minecraft crashes with an error. Here is the log https://drive.google.com/file/d/1o-2R6KZaC8sxjtLaw5qj0A-GkG_SuoB5/view?usp=sharing
    • The specific issue is that items in my inventory wont stack properly. For instance, if I punch a tree down to collect wood, the first block I collected goes to my hand. So when I punch the second block of wood to collect it, it drops, but instead of stacking with the piece of wood already in my hand, it goes to the second slot in my hotbar instead. Another example is that I'll get some dirt, and then when I'm placing it down later I'll accidentally place a block where I don't want it. When I harvest it again, it doesn't go back to the stack that it came from on my hotbar, where it should have gone, but rather into my inventory. That means that if my inventory is full, then the dirt wont be picked up even though there should be space available in the stack I'm holding. The forge version I'm using is 40.3.0, for java 1.18.2. I'll leave the mods I'm using here, and I'd appreciate it if anybody can point me in the right direction in regards to figuring out how to fix this. I forgot to mention that I think it only happens on my server but I&#39;m not entirely sure. PLEASE HELP ME! LIST OF THE MODS. aaa_particles Adorn AdvancementPlaques AI-Improvements AkashicTome alexsdelight alexsmobs AmbientSounds amwplushies Animalistic another_furniture AppleSkin Aquaculture aquamirae architectury artifacts Atlas-Lib AutoLeveling AutoRegLib auudio balm betterfpsdist biggerstacks biomancy BiomesOPlenty blockui blueprint Bookshelf born_in_chaos Botania braincell BrassAmberBattleTowers brutalbosses camera CasinoCraft cfm (MrCrayfish’s Furniture Mod) chat_heads citadel cloth-config Clumps CMDCam CNB cobweb collective comforts convenientcurioscontainer cookingforblockheads coroutil CosmeticArmorReworked CozyHome CrabbersDelight crashexploitfixer crashutilities Create CreativeCore creeperoverhaul cristellib crittersandcompanions Croptopia CroptopiaAdditions CullLessLeaves curios curiouslanterns curiouslights Curses' Naturals CustomNPCs CyclopsCore dannys_expansion decocraft Decoration Mod DecorationDelightRefurbished Decorative Blocks Disenchanting DistantHorizons doubledoors DramaticDoors drippyloadingscreen durabilitytooltip dynamic-fps dynamiclights DynamicTrees DynamicTreesBOP DynamicTreesPlus Easy Dungeons EasyAnvils EasyMagic easy_npc eatinganimation ecologics effective_fg elevatorid embeddium emotecraft enchantlimiter EnchantmentDescriptions EnderMail engineersdecor entityculling entity_model_features entity_texture_features epicfight EvilCraft exlinefurniture expandability explosiveenhancement factory-blocks fairylights fancymenu FancyVideo FarmersDelight fast-ip-ping FastSuite ferritecore finsandtails FixMySpawnR Forge Middle Ages fossil FpsReducer2 furnish GamingDeco geckolib goblintraders goldenfood goodall H.e.b habitat harvest-with-ease hexerei hole_filler huge-structure-blocks HunterIllager iammusicplayer Iceberg illuminations immersive_paintings incubation infinitybuttons inventoryhud InventoryProfilesNext invocore ItemBorders itemzoom Jade jei (Just Enough Items) JetAndEliasArmors journeymap JRFTL justzoom kiwiboi Kobolds konkrete kotlinforforge lazydfu LegendaryTooltips libIPN lightspeed lmft lodestone LongNbtKiller LuckPerms Lucky77 MagmaMonsters malum ManyIdeasCore ManyIdeasDoors marbledsarsenal marg mcw-furniture mcw-lights mcw-paths mcw-stairs mcw-trapdoors mcw-windows meetyourfight melody memoryleakfix Mimic minecraft-comes-alive MineTraps minibosses MmmMmmMmmMmm MOAdecor (ART, BATH, COOKERY, GARDEN, HOLIDAYS, LIGHTS, SCIENCE) MobCatcher modonomicon mods_optimizer morehitboxes mowziesmobs MutantMonsters mysticalworld naturalist NaturesAura neapolitan NekosEnchantedBooks neoncraft2 nerb nifty NightConfigFixes nightlights nocube's_villagers_sell_animals NoSeeNoTick notenoughanimations obscure_api oculus oresabovediamonds otyacraftengine Paraglider Patchouli physics-mod Pillagers Gun PizzaCraft placeableitems Placebo player-animation-lib pneumaticcraft-repressurized polymorph PrettyPipes Prism projectbrazier Psychadelic-Chemistry PuzzlesLib realmrpg_imps_and_demons RecipesLibrary reeves-furniture RegionsUnexplored restrictedportals revive-me Scary_Mobs_And_Bosses selene shetiphiancore ShoulderSurfing smoothboot
    • Hi everyone, I'm currently developing a Forge 1.21 mod for Minecraft and I want to display a custom HUD overlay for a minigame. My goal: When the game starts, all players should see an item/block icon (from the base game, not a custom texture) plus its name/text in the HUD – similar to how the bossbar overlay works. The HUD should appear centered above the hotbar (or at a similar prominent spot), and update dynamically (icon and name change as the target item changes). What I've tried: I looked at many online tutorials and several GitHub repos (e.g. SeasonHUD, MiniHUD), but most of them use NeoForge or Forge versions <1.20 that provide the IGuiOverlay API (e.g. implements IGuiOverlay, RegisterGuiOverlaysEvent). In Forge 1.21, it seems that neither IGuiOverlay nor RegisterGuiOverlaysEvent exist anymore – at least, I can't import them and they are missing from the docs and code completion. I tried using RenderLevelStageEvent as a workaround but it is probably not intended for custom HUDs. I am not using NeoForge, and switching the project to NeoForge is currently not an option for me. I tried to look at the original minecraft source code to see how elements like hearts, hotbar etc are drawn on the screen but I am too new to Minecraft modding to understand. What I'm looking for: What is the correct way to add a custom HUD element (icon + text) in Forge 1.21, given that the previous overlay API is missing? Is there a new recommended event, callback, or method in Forge 1.21 for custom HUD overlays, or is everyone just using a workaround? Is there a minimal open-source example repo for Forge 1.21 that demonstrates a working HUD overlay without relying on NeoForge or deprecated Forge APIs? My ideal solution: Centered HUD element with an in-game item/block icon (from the base game's assets, e.g. a diamond or any ItemStack / Item) and its name as text, with a transparent background rectangle. It should be visible to the players when the mini game is running. Easy to update the item (e.g. static variable or other method), so it can change dynamically during the game. Any help, code snippets, or up-to-date references would be really appreciated! If this is simply not possible right now in Forge 1.21, it would also help to know that for sure. Thank you very much in advance!
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.