Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

How to set texture for dynamically registered blocks from already existing blocks [1.18.2]


X-Lomir
 Share

Recommended Posts

  • Replies 150
  • Created
  • Last Reply

Top Posters In This Topic

Posted (edited)

I managed to solve the overlay texture problem by doing this:

public class FMLClientSetupEventHandler {
  /**
   * Sets the correct {@link RenderType} for {@link crystalspider.justverticalslabs.blocks.VerticalSlabBlock VerticalSlabBlocks}.
   * 
   * @param event
   */
  @SubscribeEvent
  public void setup(FMLClientSetupEvent event) {
    event.enqueueWork(() -> {
      // TODO: Check if it works also for translucent blocks.
      ItemBlockRenderTypes.setRenderLayer(JustVerticalSlabsLoader.VERTICAL_SLAB_BLOCK.get(), RenderType.cutoutMipped());
    });
  }
}

I also tried to solve the color problem by doing this:

public class ColorHandlerEventHandler {
  @SubscribeEvent
  public void onColorHandlerEventBlock(ColorHandlerEvent.Block event) {
    event.getBlockColors().register(new BlockColor() {
      public int getColor(BlockState state, @Nullable BlockAndTintGetter getter, @Nullable BlockPos pos, int tintIndex) {
        if (getter != null && pos != null) {
          BlockState referredSlabState = VerticalSlabUtils.getReferredSlabState(getter, pos);
          if (referredSlabState != null) {
            Block slab = referredSlabState.getBlock();
            if (slab instanceof GrassBlock || slab instanceof LeavesBlock) {
              return event.getBlockColors().getColor(Block.byItem(VerticalSlabUtils.slabMap.get(slab.asItem())).defaultBlockState(), getter, pos, tintIndex);
            }
          }
        }
        return -1;
      }
    }, JustVerticalSlabsLoader.VERTICAL_SLAB_BLOCK.get());
  }

  @SubscribeEvent
  public void onColorHandlerEventItem(ColorHandlerEvent.Item event) {
    event.getItemColors().register(new ItemColor() {
      public int getColor(ItemStack itemStack, int tintIndex) {
        BlockState referredSlabState = VerticalSlabUtils.getReferredSlabState(itemStack);
        if (referredSlabState != null) {
          Block slab = referredSlabState.getBlock();
          if (slab instanceof GrassBlock || slab instanceof LeavesBlock) {
            return event.getItemColors().getColor(VerticalSlabUtils.slabMap.get(slab.asItem()).getDefaultInstance(), tintIndex);
          }
        }
        return -1;
      }
    }, JustVerticalSlabsLoader.VERTICAL_SLAB_ITEM.get());
  }
}

And I tried registering this class first with

FMLJavaModLoadingContext.get().getModEventBus().register(new ColorHandlerEventHandler());

and after with 

MinecraftForge.EVENT_BUS.register(new ColorHandlerEventHandler());

however either way I get this (and no errors):

https://imgur.com/a/M9sfwVw

EDIT: I forgot to add that I moved the code in this new branch.

Edited by X-Lomir
Added extra info.
Link to comment
Share on other sites

In the end it was just me being stupid. What you said I had already did by using the tint index of the referred sprite rather than of my model JSON.

The real problem was that I was checking instanceof on the slab, but I needed to check on the block.

I changed my code to this and it works:

public class ColorHandlerEventHandler {
  @SubscribeEvent
  public void onColorHandlerEventBlock(ColorHandlerEvent.Block event) {
    event.getBlockColors().register(new BlockColor() {
      public int getColor(BlockState state, @Nullable BlockAndTintGetter getter, @Nullable BlockPos pos, int tintIndex) {
        if (getter != null && pos != null) {
          BlockState referredSlabState = VerticalSlabUtils.getReferredSlabState(getter, pos);
          if (referredSlabState != null) {
            // Edited here
            Block block = Block.byItem(VerticalSlabUtils.slabMap.get(referredSlabState.getBlock().asItem()));
            if (block instanceof GrassBlock || block instanceof LeavesBlock) {
              return event.getBlockColors().getColor(block.defaultBlockState(), getter, pos, tintIndex);
            }
          }
        }
        return -1;
      }
    }, JustVerticalSlabsLoader.VERTICAL_SLAB_BLOCK.get());
  }

  @SubscribeEvent
  public void onColorHandlerEventItem(ColorHandlerEvent.Item event) {
    event.getItemColors().register(new ItemColor() {
      public int getColor(ItemStack itemStack, int tintIndex) {
        BlockState referredSlabState = VerticalSlabUtils.getReferredSlabState(itemStack);
        if (referredSlabState != null) {
          // Edited here
          Block block = Block.byItem(VerticalSlabUtils.slabMap.get(referredSlabState.getBlock().asItem()));
          if (block instanceof GrassBlock || block instanceof LeavesBlock) {
            return event.getItemColors().getColor(block.asItem().getDefaultInstance(), tintIndex);
          }
        }
        return -1;
      }
    }, JustVerticalSlabsLoader.VERTICAL_SLAB_ITEM.get());
  }
}

The correct bus seems to be FMLJavaModLoadingContext.get().getModEventBus().

Link to comment
Share on other sites

38 minutes ago, diesieben07 said:

Why do you even have that instanceof check? You can just call BlockColors / ItemColors#getColor directly for all blocks. Not just grass and leaves can be colored.

Yeah you're right. I thought I would break colors of normal blocks if I did that, I don't know why.

Link to comment
Share on other sites

I noticed that some mods can add slabs for blocks that are not full height, like soulsand and dirt path. That caused a couple of problems with my vertical slabs, however I managed to make so that vertical slabs can also be not full height and their textures adapt too.

There is one problem that arose which is that vertical slabs not full height still make other blocks cull their faces: https://imgur.com/a/ZBUpszZ

I don't know why this is happening nor how to solve this. You can see the textures and the shape of the vertical slab being correct, however it's as if it's considered as a full height block.

Code is here.

Link to comment
Share on other sites

Okay, thanks, it works.

I'm testing my mod with transparent slabs, like glass, and, as I expected given I set the render layer as cutout mipped, transparent blocks don't work well at all.

Is there a way to set the render layer depending on the block entity? Or what else could I do to make so that only vertical slabs referring transparent blocks are rendered in translucent render layer?

Link to comment
Share on other sites

No, RenderType can only be set on the Block level (not even BlockState). You'll have to make multiple blocks, one for each RenderType you want to support.

However then you still need a hardcoded map that stores which Block maps to which RenderType, because this information is normally not available server side.

Link to comment
Share on other sites

2 hours ago, diesieben07 said:

No, RenderType can only be set on the Block level (not even BlockState). You'll have to make multiple blocks, one for each RenderType you want to support.

However then you still need a hardcoded map that stores which Block maps to which RenderType, because this information is normally not available server side.

Okay, I figured out as much. I guess I will make another kind of block and use it for certain blocks on a best-effort base, like checking if the ID of the mimicked block contains "glass", "leaf", "leaves", or something like that. Maybe add a config option to add another keyword to use to render a specific kind of block with the translucent layer.

Link to comment
Share on other sites

Posted (edited)

I added a class for transparent vertical slabs. Everything works fine so far except one thing that is transparent vertical slabs still cull their faces and the faces of their neighboring blocks.

Is there some method or property I can override in my new class or do I necessarily have to duplicate my JSON models and remove the cullfaces?

EDIT: I found getOcclusionShape and it looks like it's working.

Edited by X-Lomir
Added found solution.
Link to comment
Share on other sites

It was pointed out to me a bug my mod has when using shaders other than Minecraft defaults, for example with Optifine internal shaders and BSL Shaders.

The bug consists in all textures, apart from the oak planks, for my vertical slabs to be completely messed up. I guess this has to do with how I'm forcefully writing in the vertexes of my model.

Is there a way to test and debug my mod with Optifine and, optionally, an external shader pack?

Do you have any suggestions or insights about what may be causing the problem and how to fix it? I'm also trying to ask for some help on Minecraft Shaders Discord, I'll update here if I find a solution.

Link to comment
Share on other sites

I managed to solve the issue. The fix was actually quite simple, and I'm also not exactly sure why it works, but it does and I'm satisfied with it 🤣

I think it works because the BLOCK VertexFormat has, in order, a position element, a color element and the 2 UVs elements. A position elements uses 3 vertex elements (x, y and z), a color element takes 1 vertex element, U and V elements take 1 vertex element each. So the index for U is 3 + 1 + vertexIndex, where vertexIndex is the index of the current vertex, which increases every iteration by the size each vertex takes in the vertices array. Similarly, the index for V is 3 + 1 + vertexIndex + 1, accounting for the previous U vertex element.

However I'm not sure this is the correct explanation, but I'll leave here my intuition and the fixed method to update vertices:

private int[] updateVertices(int[] vertices, int[] referredVertices, TextureAtlasSprite oldSprite, TextureAtlasSprite newSprite, boolean faceUp) {
  int[] updatedVertices = vertices.clone();
  for (int vertexIndex = 0; vertexIndex < DefaultVertexFormat.BLOCK.getVertexSize(); vertexIndex += DefaultVertexFormat.BLOCK.getIntegerSize()) {
    float y = Float.intBitsToFloat(referredVertices[vertexIndex + 1]);
    // Lower only top face since RenderType CutoutMipped will remove extra transparent texture bits that go out of the shape. 
    if (faceUp && y > 0 && y < 0.5) {
      updatedVertices[vertexIndex + 1] = Float.floatToRawIntBits(y + 0.5F);
    }
    updatedVertices[vertexIndex + 4] = changeUVertexSprite(oldSprite, newSprite, updatedVertices[vertexIndex + 4]);
    updatedVertices[vertexIndex + 5] = changeVVertexSprite(oldSprite, newSprite, updatedVertices[vertexIndex + 5]);
  }
  return updatedVertices;
}

 

Link to comment
Share on other sites

I'm wondering... Couldn't I put a property into my BlockState that will hold the referredBlockState?

Basically in VerticalSlabBlock#getStateForPlacement I could read the NBT tag from the itemstack and save it in my BlockState, the same way I do for light. This way I could get rid of BEs altogether and make better use of BlockState chaching system. Also it would allow my blocks to be pushed by pistons and to mimic properties I currently cannot mimic because their getter only takes a BlockState as input.

The only problem I can see would be how to handle VerticalSlabBakedModel#getQuads because of that thing with the breaking progress animation.

Link to comment
Share on other sites

No, you can't do that.

BlockStates need to have a finite set of values, they are all precomputed. If you have more than a couple block states for your block, the system breaks. Apart from that, you'd break worlds as soon as other mods are added or removed (or the amount of slabs changes), because your block state changed.

Link to comment
Share on other sites

I'm trying to put my mod on a server and I get this error:

-- Head --
Thread: main
Stacktrace:
        at cpw.mods.cl.ModuleClassLoader.loadClass(ModuleClassLoader.java:138) ~[securejarhandler-1.0.3.jar:?] {}
-- MOD justverticalslabs --
Details:
        Caused by 0: java.lang.reflect.InvocationTargetException
                at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
                at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
                at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
                at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
                at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
                at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:67) ~[javafmllanguage-1.18.2-40.1.20.jar%23126!/:?] {}
                at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:106) ~[fmlcore-1.18.2-40.1.20.jar%23125!/:?] {}
                at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
                at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
                at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
                at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
                at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {re:computing_frames}
                at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {re:computing_frames}
                at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}

        Caused by 1: java.lang.NoClassDefFoundError: net/minecraft/client/color/item/ItemColor
                at crystalspider.justverticalslabs.JustVerticalSlabsLoader.<init>(JustVerticalSlabsLoader.java:159) ~[justverticalslabs-1.18.2-3.0.0.0.jar%2390!/:1.18.2-3.0.0.0] {re:classloading}
                at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
                at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
                at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
                at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
                at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
                at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:67) ~[javafmllanguage-1.18.2-40.1.20.jar%23126!/:?] {}
                at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:106) ~[fmlcore-1.18.2-40.1.20.jar%23125!/:?] {}
                at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
                at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
                at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
                at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
                at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {re:computing_frames}
                at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {re:computing_frames}
                at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}

        Mod File: justverticalslabs-1.18.2-3.0.0.0.jar
        Failure message: Just Vertical Slabs (justverticalslabs) has failed to load correctly
                java.lang.reflect.InvocationTargetException: null
        Mod Version: 1.18.2-3.0.0.0
        Mod Issue URL: https://github.com/Nyphet/just-vertical-slabs/issues
        Exception message: java.lang.ClassNotFoundException: net.minecraft.client.color.item.ItemColor
Stacktrace:
        at cpw.mods.cl.ModuleClassLoader.loadClass(ModuleClassLoader.java:138) ~[securejarhandler-1.0.3.jar:?] {}
        at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?] {}
        at crystalspider.justverticalslabs.JustVerticalSlabsLoader.<init>(JustVerticalSlabsLoader.java:159) ~[justverticalslabs-1.18.2-3.0.0.0.jar%2390!/:1.18.2-3.0.0.0] {re:classloading}
        at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
        at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
        at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
        at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
        at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
        at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:67) ~[javafmllanguage-1.18.2-40.1.20.jar%23126!/:?] {}
        at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:106) ~[fmlcore-1.18.2-40.1.20.jar%23125!/:?] {}
        at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
        at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
        at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
        at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {re:computing_frames}
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {re:computing_frames}
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}

How do I fix this? Should I put a @OnlyIn(Dist.CLIENT) in my color event handler class? Or add a check for the side in the methods that register BlockColors and ItemColors? Or something else entirely?

Link to comment
Share on other sites

38 minutes ago, diesieben07 said:

Do not use @OnlyIn.

You should use a separate @EventBusSubscriber with the Dist.CLIENT argument for a client-only event handler and do all your client only event handling there.

I did this:

@EventBusSubscriber(value = Dist.CLIENT, bus = Bus.MOD)
public class ColorHandlerEventHandler

And removed the manual subscribing in my mod loader class.

However now in single player my grass vertical slabs are back to being greyscale.

Link to comment
Share on other sites

Here the code of the handler class.

It is not updated with the annotation, however all I did in local was to add the annotation as shown before and remove the line to register that class in my mod loader class.

Before this change it would crash when server side only, but would color correctly in single player.

After this change it's not coloring correctly in single player. I didn't check if it fixed the crash server side.

Link to comment
Share on other sites

Thanks, it works now!

I found another problem unfortunately: when the version of the mod that's on the client tries to access the volatile immutable maps the game crashes. The issue is that those maps are never instantiated on the client.

How do I fix this? Do I have to register a packet and every time I want to access those maps I must send and receive a packet? Or is there a smarter way?

Also I'm wondering why on the Forge docs it's written to use a separate class when creating a simple channel object. Wouldn't it be okay if I did it in my JustVerticalSlabsLoader?

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
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.

 Share




×
×
  • Create New...

Important Information

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