@JamesTheAwesomeDude opened this Issue on January 23rd 2021 Contributor


X-Wurst is (still) incompatible with Sodium. I tested it myself on a fresh profile today.

While, unfortunately, the OptiFine dev is being petty and combative about this, making #174 conceptually wontfix/upstream-blocked, I see that, with Sodium, there are no such artificial obstacles (and it's open-source, to boot).

I'd like to formally open the ticket on this. Sodium has been a life-saver for me.

@EcoBuilder13 commented on January 23rd 2021

@JamesTheAwesomeDude Try using Indium, it is an experiential addon for Sodium which adds Fabric Rendering API support. Make sure you read the instructions and you can either build from source or download pre-built jars from Github CI.

@holysnipz commented on January 23rd 2021

@EcoBuilder13 still not working, same result

@EcoBuilder13 commented on January 23rd 2021

@holysnipz I just looked at the code for the X-Ray hack and I think I know why Indium doesn't fix it. Indium only adds the Fabric Rending API to the game in a way that Sodium can run it. In XRayHack.java I am seeing custom rendering calls created by Wurst. This means the problem is caused with the rendering code that Wurst uses is not compatible with Sodium. The only way I see this getting fixed is if they Wurst developers make their custom rendering able with Sodium.

@XfedeX commented on January 24th 2021

that would be VERY useful!!!!!!

@Alexander01998 commented on January 26th 2021 Member

@EcoBuilder13 it's actually BlockModelRendererMixin that is having trouble with Sodium.

Sodium seems to bypass Minecraft's BlockModelRenderer.renderSmooth() and BlockModelRenderer.renderFlat() calls, so although Wurst's mixin is still applied, it doesn't do anything with Sodium (or OptiFine) installed.

It would seem that if we could find Sodium's replacement for BlockModelRenderer and mixin into that, then X-Ray would work again. Though from looking at Sodium's source code, it doesn't seem to be that simple.

@EcoBuilder13 commented on January 26th 2021

@Alexander01998 Cool, now that we know exactly what the problem is it is much easier to find a fix. I have a good feeling that Sodium replaces renderSmooth() and renderFlat() with it's own versions. I checked the mixin for BlockModelRenderer in Sodium and it does not look like it contains the new methods. I don't know the names of the new methods but there are people on their Discord server (as of posting the link times out for me I am looking to get it fixed) who know more about the internals of Sodium. For compatibility you could detect when Sodium is installed and say something like if sodiumDetected = true then foobar.sodiumRenderSmooth(); else foobar.renderSmooth();. This would basically run the Sodium rendering call when it is detected but other wise call the vanilla one so that the end user does not have to adjust settings/config. If something like that works the way I think it would.

@Alexander01998 commented on January 27th 2021 Member

I'll try to explain some more:

X-Ray works by overwriting Minecraft's decision of which blocks to render and which blocks to hide.

Normally, when Minecraft decides whether or not to render a block, it calls the following methods in order:

  1. BlockRenderManager.renderBlock()
  2. BlockModelRenderer.render()
  3. either BlockModelRenderer.renderSmooth() or BlockModelRenderer.renderFlat()

Each of these methods have a boolean cull parameter that, if set to false, causes the block to be rendered even when it's behind other blocks. This is how X-Ray can show ores that would normally be hidden.

The other thing that X-Ray needs to do is to hide all of the non-ore blocks that would normally be rendered. It does this by simply cancelling the method call.

In vanilla, that gives me three options for where to place the X-Ray logic. Currently X-Ray uses renderSmooth() / renderFlat(), but the other two would work just as well.

Now this is what happens if Sodium is installed:

  1. ???
  2. modified version of BlockModelRenderer.render() that doesn't have boolean cull
  3. BlockModelRenderer.renderQuad() (also doesn't have boolean cull)

As you can see, that seemingly leaves zero options for where to put the X-Ray logic.

So far I haven't been able to figure out what step 1 gets replaced with, I only know that the original BlockRenderManager.renderBlock() doesn't get called anymore.

Step 2 and 3 have become pretty useless for X-Ray. It could still cancel these methods, but it can't force them to render their block.

Since these methods have seemingly no logic in them for deciding which blocks to render, that gives me a suspicion that Sodium might make that decision somewhere else, before any of these methods are called. But where this happens and how it works is a mystery to me.

@x86k commented on April 2nd 2021
@LukasAppleFan commented on May 8th 2021

Any update ?

@RealIndica commented on August 15th 2021

How about you write a separate sodium compatible x-ray that doesn't mess with the blocks rendering.

Do it the old fashioned way : Loop through blocks (distance set to your render distance), get their positions, convert positions to screen positions, draw an overlay.


Hook sodium's render method and create another renderer on top of that. You will just have to make sodium's render not execute with x-ray on, but only show your own renderer. Making sodium's renderer temporally null should be fairly simple with patching.

pseudocode :

[Hook("-insert sodium block render function here-")]
class Patch 
     void Prefix() //this is called before sodiums render is called
          if (xray == true)
               //do your x-ray work here
              return false; //prevent sodiums render function from being called
               return true; //allow sodiums render function to be called

(I am a c# developer, although java is very similar I am definitely not an expert lol)