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.



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • I'm developing a dimension, but it's kinda resource intensive so some times during player teleporting it lags behind making the player phase down into the void, so im trying to implement some kind of pregeneration to force the game loading a small set of chunks in the are the player will teleport to. Some of the things i've tried like using ServerLevel and ServerChunkCache methods like getChunk() dont actually trigger chunk generation if the chunk isn't already on persistent storage (already generated) or placing tickets, but that doesn't work either. Ideally i should be able to check when the task has ended too. I've peeked around some pregen engines, but they're too complex for my current understanding of the system of which I have just a basic understanding (how ServerLevel ,ServerChunkCache  and ChunkMap work) of. Any tips or other classes I should be looking into to understand how to do this correctly?
    • https://mclo.gs/4UC49Ao
    • Way back in the Forge 1.17 days, work started for adding JPMS (Java Platform Module Support) to ModLauncher and ForgeModLoader. This has been used internally by Forge and some libraries for a while now, but mods (those with mods.toml specifically) have not been able to take advantage of it. As of Forge 1.21.1 and 1.21.3, this is now possible!   What is JPMS and what does it mean for modders? JPMS is the Java Platform Module System, introduced in Java 9. It allows you to define modules, which are collections of packages and resources that can be exported or hidden from other modules. This allows for much more fine-tuned control over visibility, cleaner syntax for service declarations and support for sealed types across packages. For example, you might have a mod with a module called `com.example.mod` that exports `com.example.mod.api` and `com.example.mod.impl` to other mods, but hides `com.example.mod.internal` from them. This would allow you to have a clean API for other mods to use, while keeping your internal implementation details hidden from IDE hints, helping prevent accidental usage of internals that might break without prior notice. This is particularly useful if you'd like to use public records with module-private constructors or partially module-private record components, as you can create a sealed interface that only your record implements, having the interface be exported and the record hidden. It's also nice for declaring and using services, as you'll get compile-time errors from the Java compiler for typos and the like, rather than deferring to runtime errors. In more advanced cases, you can also have public methods that are only accessible to specific other modules -- handy if you want internal interactions between multiple of your own mods.   How do I bypass it? We understand there may be drama in implementing a system that prevents mods from accessing each other's internals when necessary (like when a mod is abandoned or you need to fix a compat issue) -- after all, we are already modding a game that doesn't have explicit support for Java mods yet. We have already thought of this and are offering APIs from day one to selectively bypass module restrictions. Let me be clear: Forge mods are not required to use JPMS. If you don't want to use it, you don't have to. The default behaviour is to have fully open, fully exported automatic modules. In Java, you can use the `Add-Opens` and `Add-Exports` manifest attributes to selectively bypass module restrictions of other mods at launch time, and we've added explicit support for these when loading your Forge mods. At compile-time, you can use existing solutions such as the extra-java-module-info Gradle plugin to deal with non-modular dependencies and add extra opens and exports to other modules. Here's an example on how to make the internal package `com.example.examplemod.internal` open to your mod in your build.gradle: tasks.named('jar', Jar) { manifest { attributes([ 'Add-Opens' : 'com.example.examplemod/com.example.examplemod.internal' 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors // (...) ]) } } With the above in your mod's jar manifest, you can now reflectively access the classes inside that internal package. Multiple entries are separated with a space, as per Java's official spec. You can also use Add-Exports to directly call without reflection, however you'd need to use the Gradle plugin mentioned earlier to be able to compile. The syntax for Add-Exports is the same as Add-Opens, and instructions for the compile-time step with the Gradle plugin are detailed later in this post. Remember to prefer the opens and exports keywords inside module-info.java for sources you control. The Add-Opens/Add-Exports attributes are only intended for forcing open other mods.   What else is new with module support? Previously, the runtime module name was always forced to the first mod ID in your `mods.toml` file and all packages were forced fully open and exported. Module names are now distinguished from mod IDs, meaning the module name in your module-info.java can be different from the mod ID in your `mods.toml`. This allows you to have a more descriptive module name that doesn't have to be the same as your mod ID, however we strongly recommend including your mod ID as part of your module name to aid troubleshooting. The `Automatic-Module-Name` manifest attribute is now also honoured, allowing you to specify a module name for your mod without needing to create a `module-info.java` file. This is particularly useful for mods that don't care about JPMS features but want to have a more descriptive module name and easier integration with other mods that do use JPMS.   How do I use it? The first step is to create a `module-info.java` file in your mod's source directory. This file should be in the same package as your main mod class, and should look something like this: open module com.example.examplemod { requires net.minecraftforge.eventbus; requires net.minecraftforge.fmlcore; requires net.minecraftforge.forge; requires net.minecraftforge.javafmlmod; requires net.minecraftforge.mergetool.api; requires org.slf4j; requires logging; } For now, we're leaving the whole module open to reflection, which is a good starting point. When we know we want to close something off, we can remove the open modifier from the module and open or export individual packages instead. Remember that you need to be open to Forge (module name net.minecraftforge.forge), otherwise it can't call your mod's constructor. Next is fixing modules in Gradle. While Forge and Java support modules properly, Gradle does not put automatic modules on the module path by default, meaning that the logging module (from com.mojang:logging) is not found. To fix this, add the Gradle plugin and add a compile-time module definition for that Mojang library: plugins { // (...) id 'org.gradlex.extra-java-module-info' version "1.9" } // (...) extraJavaModuleInfo { failOnMissingModuleInfo = false automaticModule("com.mojang:logging", "logging") } The automatic module override specified in your build.gradle should match the runtime one to avoid errors. You can do the same for any library or mod dependency that is missing either a module-info or explicit Automatic-Module-Name, however be aware that you may need to update your mod once said library adds one. That's all you need to get started with module support in your mods. You can learn more about modules and how to use them at dev.java.
    • Faire la mise à jour grâce à ce lien m'a aider personnellement, merci à @Paint_Ninja. https://www.amd.com/en/support 
    • When I came across the 'Exit Code: I got a 1 error in my Minecraft mods, so I decided to figure out what was wrong. First, I took a look at the logs. In the mods folder (usually where you'd find logs or crash reports), I found the latest.log file or the corresponding crash report. I read it through carefully, looking for any lines with errors or warnings. Then I checked the Minecraft Forge support site, where you can often find info on what causes errors and how to fix them. I then disabled half of my mods and tried running the game. If the error disappeared, it meant that the problem was with the disabled mod. I repeated this several times to find the problem mod.
  • Topics

×
×
  • Create New...

Important Information

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