Jump to content

Custom Renderer


StevilKnevil

Recommended Posts

Hi, I've stared writing a mod and have had some good success so far (really impressed with Forge BTW!). However I think my ambitions lie somewhat outside the normal mods.

 

I want to add a special effect to any block (or ultimately tile entity). Basically I want one player to be able to mark a set of blocks and then have that set of blocks be highlighted (for all players). Perhaps something a little like the black outline on the block in the centre of the screen, but persistant and on more than one block, or maybe some glow effect... I'm thinking that I can just render transparent a (very slightly larger) block over the top of the base block. The actual rendering style is to be decided, but I'm guessing it wouldn't affect the implementation too much.

 

I've had a look through this forum as best I can and I've also dug through this tutorial:

 

http://www.minecraftforge.net/wiki/Multiple_Pass_Render_Blocks

 

but I've not had much success so far.

 

Ideally I want to avoid modifying core Minecraft code, and keep all my code nicely isolated, so adding a new render pass doesn't seem like a good idea (for a number of reasons!). There seem to be a couple of pre/post block render Forge hooks but they seem to be commented out at the moment. I also don't think that would be the right place because if a block is not rendered in the transparent pass then it wouldn't get the hooks called that would allow me to overlay a glow.

 

I've seen that there's a ISimpleBlockRenderingHandler, but I think if I implemented that then it would only get called for non-vanilla blocks, whereas I really want to be able to be able to do this for all blocks without having to customise all the existing blocks.

 

Hopefully that's a decent enough description, could any one give me any pointers of things to look into? I'm happy to consider entirely different methods of achieving the same results by the way! but I am keen to keep the code as simple and non-invasive as possible. I just need a foot in the door, some places to put breakpoints and some code to read :)

 

Thanks in advance!

Link to comment
Share on other sites

FYI After a few more searches I found this, which might be an option to try:

 

you could technicly make an invisible entity that has information about the width/height/length of the protected area and x, y,z  and use this entity to draw a big box that represents the limit of the area.

Link to comment
Share on other sites

FYI After a few more searches I found this, which might be an option to try:

 

you could technicly make an invisible entity that has information about the width/height/length of the protected area and x, y,z  and use this entity to draw a big box that represents the limit of the area.

 

hey thats ME :D!!!!

 

but yeah thats probably the best way to go unless you feel like doing ASM....... no come to think of it if you want the OTHER players to see it, its the only way to go

how to debug 101:http://www.minecraftforge.net/wiki/Debug_101

-hydroflame, author of the forge revolution-

Link to comment
Share on other sites

hey thats ME :D!!!!

 

:D

 

but yeah thats probably the best way to go unless you feel like doing ASM....... no come to think of it if you want the OTHER players to see it, its the only way to go

 

ASM? I did actually think another way might be to do some code injection to (for example) modify the WorldRenderer... but I think that's probably bordering on yuk ;-)

Link to comment
Share on other sites

So I've got this kinda working for using entities to do this, but I'm tending away from this idea now. The 'highlighting' of the blocks is something that is going to change relatively infrequently (e.g. about as often as block creation/destruction) rather than every frame. I think it would be more efficient to have it as part of the block render list rather than an entity that is updated every frame.

 

Or am I misundertanding how the block render lists are built?

 

NB I've got no idea yet on how I'll achieve it!

Link to comment
Share on other sites

I've got something working, but it's not the least invasive thing ever!

 

I extended the BlocksRederer to be a BlockEffectRenderer. It's still responsible for rendering the blocks themselves, but it also has the option to render a BlockEffect for each block it handles.

 

I had to do this because the block effect might be in renderpass 1, but if the block only renders in renderpass 0 then it all goes wrong :)

 

So I needed to modify WorldRenderer to instantiate (and call) my BlockEffectRenderer, which was only around 5 lines of code that needed changing, but I might try and tweak it a bit more to clean it up even more.

Link to comment
Share on other sites

Perhaps a bit of a different method:

 

There is a renderWorldLast event--called after other world rendering to allow you to render things in ...the world.

 

You would need to synch a list of the 'highlighted' blocks between server + clients (packets, basic synch stuff), but then could simply use the renderWorldLast event to directly render your highlights -- no need for entities and the overhead they bring, or trying to use block renderers.  Using the event, you could theoretically render...anything you wanted. It seems to work well with transparency and occlusion (I have it rendering large bounding boxes around block-selections as well, using semi-transparent lines).

 

(see https://github.com/shadowmage45/AncientWarfare/blob/master/AncientWarfare/src/shadowmage/ancient_warfare/client/render/AWRenderHelper.java#L201 for examples)

 

 

Link to comment
Share on other sites

There is a renderWorldLast event--called after other world rendering to allow you to render things in ...the world.

 

This is really useful stuff (and I'll definitely be using that hook) but for this particular use case the special effects on the blocks are relatively unchanging between frames rather than changing every frame; so for efficiencies sake I think it's better to bake this stuff into the render lists for the chunk rather than pay the per frame costs of rendering the effects.

 

Please correct me if I'm mistaken!

Link to comment
Share on other sites

You may very well be correct about the per-frame costs.  The renderWorldLast method doesn't have an easy way to setup/call an optimized displayList, so it has to rebuild/recalculate per-frame.  I am by no means a rendering expert though, so others may have more accurate info/input on it.

 

Please keep us informed if you do find a better process to accomplish your goal, would be interested in hearing about it :)

Link to comment
Share on other sites

I am by no means a rendering expert though, so others may have more accurate info/input on it.

*puts on glasses*

afaik there is no way to do that, for some reason mc uses displayList for 99% of the blocks then TileEntitySpecialRenderer for the other 1%, the thign that i hate is that there is no middle, you either need a TileEntity or you dont and cant use animation/render every frame .... :\ optifine has something for that but unfortunatelly that a mod in itself and now included in vanilla mc

how to debug 101:http://www.minecraftforge.net/wiki/Debug_101

-hydroflame, author of the forge revolution-

Link to comment
Share on other sites

Please keep us informed if you do find a better process to accomplish your goal, would be interested in hearing about it :)

 

My best thinking at the moment is to do something like this in WorldRender:

 

                                    if (block != null)
                                    {
                                        if (l1 == 0 && block.hasTileEntity(chunkcache.getBlockMetadata(k2, i2, j2)))
                                        {
                                            TileEntity tileentity = chunkcache.getBlockTileEntity(k2, i2, j2);

                                            if (TileEntityRenderer.instance.hasSpecialRenderer(tileentity))
                                            {
                                                this.tileEntityRenderers.add(tileentity);
                                            }
                                        }

                                        int i3 = block.getRenderBlockPass();

                                        if (i3 > l1)
                                        {
                                            flag = true;
                                        }
                                        // !!! NEW: Slight change here !!!
                                        if (block.canRenderInPass(l1))
                                        {
                                            flag1 |= renderblocks.renderBlockByRenderType(block, k2, i2, j2);
                                        }
                                    }
                                     
                                    // !!! NEW !!!
                                    // Note that this can happen on air blocks (i.e. block == null)
                                    {
                                    	/*
                                         * to handle special effects for blocks
                                         */
                                        int i3 = ForgeHooksClient.getBlockEffectRenderPass(block, k2, i2, j2);

                                        if (i3 > l1)
                                        {
                                            flag = true;
                                        }
                                        if (i3 == l1)
                                        {
                                        	// This is the correct render pass for this block effect
                                        	flag1 |= ForgeHooksClient.renderBlockEffect(block, k2, i2, j2);
                                        }
                                    }
                                    // !!! END NEW !!!

Link to comment
Share on other sites

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

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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