Jump to content

Recommended Posts

Posted (edited)

I'm wondering how I can render fixed lines between tile entities in a simular way to buildcraft markers or immersive engineering wires.

The actual rendering and render types i've figured out and I have it rendering from a single tile to a player mostly using mcjtys tutorial https://wiki.mcjty.eu/modding/index.php?title=Tut15_Ep15 for tile entity rendering.

the issue is that I essentially have a kind of linked list of a bunch of points that are all linked together using real world positions but to draw this on the clientside relative to the player seems incredibly difficult since the only event I can think of
is the client tick events and then I don't know how I would grab the matrix stack equivalent positions relative to the player from the actual positions within the world. I'm not sure if thats even possible.

 

The vast majority of the code is essentially very simular to mcjtys tutorial code with a few very minor edits so for a better reference: https://wiki.mcjty.eu/modding/index.php?title=Tut15_Ep15 for tile entity rendering.


Tile > player method (currently works)

static void drawTileToPlayer(TileEntity tile, ClientPlayerEntity player, MatrixStack matrixStack){
        IRenderTypeBuffer.Impl buffer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
        IVertexBuilder lineBuilder = buffer.getBuffer(CustomRenderTypes.THICK_LINES);

        BlockPos playerPos = player.getPosition();
        BlockPos tilePos = tile.getPos();
        int px = playerPos.getX();
        int py = playerPos.getY();
        int pz = playerPos.getZ();

        float[] lineColour = getLineColour(tile.getBlockState().getBlock());
        drawLine(lineBuilder, generateProjectedMatrix(matrixStack),tilePos.getX() + 0.5f,tilePos.getY() + 0.6f,tilePos.getZ() + 0.5f, px + 0.5f, py + 0.5f, pz + 0.5f, lineColour);

        matrixStack.pop();
        buffer.finish(CustomRenderTypes.THICK_LINES);
    }

This draws a line from the tile to the player position using a matrix stack from the renderworldlastevent event.

Generate projected matrix

private static Matrix4f generateProjectedMatrix(MatrixStack matrixStack){
        //  Begin pushing to the matrix stack.
        matrixStack.push();

        //  Get actual position of player and translate back to the actual location. E.g. blockpos is discrete integers. projected view isn't.
        Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
        matrixStack.translate(-projectedView.x, -projectedView.y, -projectedView.z);

        return matrixStack.getLast().getMatrix();
    }

 

Drawline method

private static void drawLine(IVertexBuilder builder, Matrix4f posMatrix, float x1, float y1, float z1, float x2, float y2, float z2, float[] colour){
        builder.pos(posMatrix, x1, y1, z1)
                .color(colour[0], colour[1], colour[2], colour[3])
                .endVertex();
        builder.pos(posMatrix, x2, y2, z2)
                .color(colour[0], colour[1], colour[2], colour[3])
                .endVertex();
    }


I did think of using blocks simular to string that would generate between the marker points as they are placed but unlike buildcraft i'm fixing where you can place the markers in the X & Z planes but not in the Y plane so that wont work.
 

Edited by profjb58
Posted

So i've managed to get it working (partially). I've attached an image of it.
Essentially it kinda works. It renders properly but say if another render event happens during when I place the markers down, this line gets broken. It also produces a random pattern when logging back in and out. This is acctually kinda cool and i'm guessing is because the render world last event is essentially pretty much random.

 

static void drawTileToTile(TileEntity tileStart, TileEntity tileEnd, ClientPlayerEntity player, MatrixStack matrixStack){
        IRenderTypeBuffer.Impl buffer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
        IVertexBuilder lineBuilder = buffer.getBuffer(CustomRenderTypes.THICK_LINES);
        
        BlockPos tileStartPos = tileStart.getPos();
        BlockPos tileEndPos = tileEnd.getPos();

        float[] lineColour = getLineColour(tileStart.getBlockState().getBlock());
        drawLine(lineBuilder, generateProjectedMatrix(matrixStack),tileStartPos.getX() + 0.5f,tileStartPos.getY() + 0.6f,tileStartPos.getZ() + 0.5f,
                tileEndPos.getX() + 0.5f, tileEndPos.getY() + 0.5f, tileEndPos.getZ() + 0.5f, lineColour);

        matrixStack.pop();
        buffer.finish(CustomRenderTypes.THICK_LINES);
    }

Modified code for drawing between tiles. I included

2020-07-06_23.57.25.jpg

2020-07-07_00.02.07.jpg

Posted

I also have all the positions I need for the next and previous tiles (markers) within the NBT storage of each marker so i'm wondering if using the TER approach would be better since I don't need the position of the player.

Posted

Howdy

I would suggest that you should use the TER to render your lines.

Since your TileEntity stores the position of the next marker, just draw a line to the next position (relative to the position of the TE being drawn, of course).  Very simple, very scaleable.  renderworldlastevent should be a last resort I think.

The only likely issue is that lines will disappear when the TE is unloaded (goes out of chunk range), which may become very noticeable if the markers are far apart from each other, i.e. you are close to one of the markers when the next marker goes off the edge of the chunk limit.

 

You could probably work around this by drawing to both the previous and the next markers; if necessary keeping track of which lines have already been drawn during that frame so that you don't draw the same line twice.

 

-TGG

 

 

  • Thanks 1
Posted (edited)

I had a quick go last night thinking that might be the best approach. I'm almost certain it's the only approach that would be scaleable now.
The idea of drawing 2 lines from either marker so either one is unlikely to stop rendering upon unloading a chunk is a brilliant idea, thank you. Since I have previous and next positions that is entirely possible for every marker as well.

The only problems i'm having now is the ability to update the rendering based upon the information of the connected tile entities (markers) updating. E.g. one being removed or added. I have the correct methods overrided and sending data, e.g. onDataPacket, getUpdatePacket. I think I might be missing something here. I'll send the code for it.
There is also a weird effect whereby once the player stops looking at the tile the connecting tiles lines dissapear. Thinking about it though drawing 2 lines between the markers would fix this I think.


gist link: https://gist.github.com/profjb58/3b7960e437386228c3f472bd05e49764
(A lot of code, didn't want to spam this thread)


I think i'm limiting the amount of data I sync to the client from what I can tell to only include

  • 'connectedFacing > direction the marker is pointing'
  • 'isTail' > is this marker the tail of the list.
  • prevMarker & nextMarker' *

* The only variables required for the TER. everything else used for drawing a line from the tail (end marker) to the player.


p.s. the gist code is a bit of a mess. It works but i'm sure there is a better way of laying it out.
 

Edited by profjb58
pastebin sucks
  • 2 weeks later...

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

    • 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!
    • The simple answer is there is not an easy way. You would need to know how to program in Java, as well as at least some familiarity with how Forge works so you could port the differences. You would also need the sourcecode for the original mod, and permission from the author to modify it, if they did not use some sort of open source license. So it's not impossible, but it would take some effort, but doing so would open up a whole new world of possibilities for you!
    • Does it still crash if you remove holdmyitems? Looks like that mod doesn't work on a server as far as I can tell from the error.  
    • Crashes the server when trying to start. Error code -1. Log  
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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