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

    • logs too big for one pastebin https://pastebin.com/ZjUGHu3u  https://pastebin.com/RqCUZf3X  https://pastebin.com/6ZPS99nD
    • You probably used jd-gui to open it, didn't you? Nothing wrong with that, I also made that mistake, except that Notch was a smart guy and he obfuscated the code. That's why you only see files called "a", "b", "c" and then a file that combines them all. As I said, use RetroMCP to deobfuscate the code so that you will 100% understand it and be able to navigate it.
    • Decompiling minecraft indev, infdev, alpha, beta or whichever legacy version is really easy. I'm not a plug, I just also got interested in modding legacy versions (Infdev to be specific). Use https://github.com/MCPHackers/RetroMCP-Java Once you install their client and the Zulu Architecture that they say they recommend (or use your own Java). I encountered some problems, so I run it with: "java -jar RetroMCP-Java-CLI.jar". You should run it in a seperate folder (not in downloads), otherwise the files and folders will go all over the place. How to use RetroMCP: Type setup (every time you want change version), copy-paste the version number from their list (they support indev), write "decompile" and done! The code will now be deobfuscated and filenames will be normal, instead of "a", "b" and "c"! Hope I helped you, but I don't expect you to reply, as this discussion is 9 years old! What a piece of history!  
    • I know that this may be a basic question, but I am very new to modding. I am trying to have it so that I can create modified Vanilla loot tables that use a custom enchantment as a condition (i.e. enchantment present = item). However, I am having trouble trying to implement this; the LootItemRandomChanceWithEnchantedBonusCondition constructor needs a Holder<Enchantment> and I am unable to use the getOrThrow() method on the custom enchantment declared in my mod's enchantments class. Here is what I have so far in the GLM:   protected void start(HolderLookup.Provider registries) { HolderLookup.RegistryLookup<Enchantment> registrylookup = registries.lookupOrThrow(Registries.ENCHANTMENT); LootItemRandomChanceWithEnchantedBonusCondition lootItemRandomChanceWithEnchantedBonusCondition = new LootItemRandomChanceWithEnchantedBonusCondition(0.0f, LevelBasedValue.perLevel(0.07f), registrylookup.getOrThrow(*enchantment here*)); this.add("nebu_from_deepslate", new AddItemModifier(new LootItemCondition[]{ LootItemBlockStatePropertyCondition.hasBlockStateProperties(Blocks.DEEPSLATE).build(), LootItemRandomChanceCondition.randomChance(0.25f).build(), lootItemRandomChanceWithEnchantedBonusCondition }, OrichalcumItems.NEBU.get())); }   Inserting Enchantments.[vanilla enchantment here] actually works but trying to declare an enchantment from my custom enchantments class as [mod enchantment class].[custom enchantment] does not work even though they are both a ResourceKey and are registered in Registries.ENCHANTMENT. Basically, how would I go about making it so that a custom enchantment declared as a ResourceKey<Enchantment> of value ResourceKey.create(Registries.ENCHANTMENT, ResourceLocation.fromNamespaceAndPath([modid], [name])), declared in a seperate enchantments class, can be used in the LootItemRandomChanceWithEnchantedBonusCondition constructor as a Holder? I can't use getOrThrow() because there is no level or block entity/entity in the start() method and it is running as datagen. It's driving me nuts.
  • Topics

×
×
  • Create New...

Important Information

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