Jump to content

Recommended Posts

Posted

I'm trying to add a liquid, called Liquid Mercury, but the game continually gives me json blockstate errors.

 

Here is one of the errors:

Spoiler

[16:17:33] [Client thread/ERROR] [FML]: Exception loading model for variant smalladditions:fluid#liquid_mercury for blockstates ["smalladditions:liquid_mercury[level=3]", "smalladditions:liquid_mercury[level=2]", "smalladditions:liquid_mercury[level=1]", "smalladditions:liquid_mercury[level=0]", "smalladditions:liquid_mercury[level=7]", "smalladditions:liquid_mercury[level=6]", "smalladditions:liquid_mercury[level=5]", "smalladditions:liquid_mercury[level=4]", "smalladditions:liquid_mercury[level=11]", "smalladditions:liquid_mercury[level=10]", "smalladditions:liquid_mercury[level=9]", "smalladditions:liquid_mercury[level=8]", "smalladditions:liquid_mercury[level=15]", "smalladditions:liquid_mercury[level=14]", "smalladditions:liquid_mercury[level=13]", "smalladditions:liquid_mercury[level=12]"]
net.minecraftforge.client.model.ModelLoaderRegistry$LoaderException: Exception loading model smalladditions:fluid#liquid_mercury with loader VariantLoader.INSTANCE, skipping
    at net.minecraftforge.client.model.ModelLoaderRegistry.getModel(ModelLoaderRegistry.java:153) ~[ModelLoaderRegistry.class:?]
    at net.minecraftforge.client.model.ModelLoader.registerVariant(ModelLoader.java:252) ~[ModelLoader.class:?]
    at net.minecraft.client.renderer.block.model.ModelBakery.loadBlock(ModelBakery.java:145) ~[ModelBakery.class:?]
    at net.minecraftforge.client.model.ModelLoader.loadBlocks(ModelLoader.java:240) ~[ModelLoader.class:?]
    at net.minecraftforge.client.model.ModelLoader.setupModelRegistry(ModelLoader.java:147) ~[ModelLoader.class:?]
    at net.minecraft.client.renderer.block.model.ModelManager.onResourceManagerReload(ModelManager.java:28) [ModelManager.class:?]
    at net.minecraft.client.resources.SimpleReloadableResourceManager.registerReloadListener(SimpleReloadableResourceManager.java:122) [SimpleReloadableResourceManager.class:?]
    at net.minecraft.client.Minecraft.startGame(Minecraft.java:540) [Minecraft.class:?]
    at net.minecraft.client.Minecraft.run(Minecraft.java:386) [Minecraft.class:?]
    at net.minecraft.client.main.Main.main(Main.java:118) [Main.class:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_102]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_102]
    at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?]
    at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_102]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_102]
    at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) [start/:?]
    at GradleStart.main(GradleStart.java:26) [start/:?]
Caused by: net.minecraft.client.renderer.block.model.ModelBlockDefinition$MissingVariantException
    at net.minecraft.client.renderer.block.model.ModelBlockDefinition.getVariant(ModelBlockDefinition.java:78) ~[ModelBlockDefinition.class:?]
    at net.minecraftforge.client.model.ModelLoader$VariantLoader.loadModel(ModelLoader.java:1195) ~[ModelLoader$VariantLoader.class:?]
    at net.minecraftforge.client.model.ModelLoaderRegistry.getModel(ModelLoaderRegistry.java:149) ~[ModelLoaderRegistry.class:?]
    ... 21 more

 

 

Here is my blockstate json (called liquid_mercury.json,): 

Spoiler

{    
    "forge_marker": 1,
    "defaults": {
        "model": "forge:fluid"
    },
    "variants": {
        "liquid_mercury": {
            "custom": { "fluid": "liquid_mercury" }
        }
    }
}
 

 

In game, the liquid works as it should; it flows and whatnot, but it is made up of cubes and is pink and black. Here's a screenshot: ZGgcD3b.png

Posted
6 hours ago, diesieben07 said:

The log clearly tells you which variant it is looking for. You do not have that variant in your blockstate.

I don't know how to add these levels to my blockstate. There's no documentation for this anywhere, as far as I can tell, so I have no idea what I'm doing. It appears as though I'm using the wrong syntax, because I keep getting malformed json errors, but I don't know what the right syntax would be.

Posted
15 hours ago, Gunmetal_Gears said:

smalladditions:fluid#liquid_mercury

This is the variant it's trying to render. That means it's looking for a blockstates file (in assets/smalladditions/blockstates) called fluid.json, and a variant in that file called "liquid_mercury". You either need to rename your file and variants, or change the ModelResourceLocation that your fluid tries to render. If you need more help, post the code where you register your fluid's state mapper etc.

Posted
19 minutes ago, Jay Avery said:

This is the variant it's trying to render. That means it's looking for a blockstates file (in assets/smalladditions/blockstates) called fluid.json, and a variant in that file called "liquid_mercury". You either need to rename your file and variants, or change the ModelResourceLocation that your fluid tries to render. If you need more help, post the code where you register your fluid's state mapper etc.

I've renamed the json to 'fluid.json' and I am getting the same errors.

Here is where I'm registering the state mapper:

Spoiler

void registerFluidModel(BlockFluidBase fluidBlock) {
        final Item item = Item.getItemFromBlock(fluidBlock);
        assert item != null;
        ModelBakery.registerItemVariants(item);
        final ModelResourceLocation modelResourceLocation = new ModelResourceLocation(FLUID_RESOURCE_PATH, fluidBlock.getFluid().getName());
        ModelLoader.setCustomMeshDefinition(item, new ItemMeshDefinition() {
            @Override
            public ModelResourceLocation getModelLocation(ItemStack stack) {
                return modelResourceLocation;
            }
        });
        ModelLoader.setCustomStateMapper(fluidBlock, new StateMapperBase() {
            @Override
            protected ModelResourceLocation getModelResourceLocation(IBlockState p_178132_1_) {
                return modelResourceLocation;
            }
        });
    }

 

Posted
2 minutes ago, Jay Avery said:

Post the latest console log (in full) and the most up-to-date blockstates file. Also, please use the code tags (<> icon), otherwise it's hard to read.

Sorry about that; I'll use those tags from now on. Here's the entire console log, from the moment I pressed run to when the game's menu opened: https://pastebin.com/LRseFTZD

Posted

I just did some poking around my own fluid rendering and I think I've found the problem. For some reason (I don't 100% understand the forge blockstates format myself...), forge doesn't seem to understand fluid blockstates if the "model" is defined in the "defaults" section and the "variant" is surrounded only by curly brackets {} . Either you need to define the model individually inside each variant:

{
  "forge_marker": 1,
  "variants": {
    "your_fluid_type": {
      "model": "forge:fluid",
      "custom": { "fluid": "your_fluid_name" }
    }
  }
}

Or you need to wrap each variant in square brackets [] too:

{
  "forge_marker": 1,
  "defaults": {
    "model": "forge:fluid"
  },
  "variants": {
    "your_fluid_type": [{
       "custom": { "fluid": "your_fluid_name" }
    }]
  }
}

 

I'm guessing it's something to do with the use of the "custom" tag, but maybe someone very knowledgeable about the forge blockstates format can explain fully.

Posted
11 minutes ago, Jay Avery said:

I just did some poking around my own fluid rendering and I think I've found the problem. For some reason (I don't 100% understand the forge blockstates format myself...), forge doesn't seem to understand fluid blockstates if the "model" is defined in the "defaults" section and the "variant" is surrounded only by curly brackets {} . Either you need to define the model individually inside each variant:


{
  "forge_marker": 1,
  "variants": {
    "your_fluid_type": {
      "model": "forge:fluid",
      "custom": { "fluid": "your_fluid_name" }
    }
  }
}

Or you need to wrap each variant in square brackets [] too:


{
  "forge_marker": 1,
  "defaults": {
    "model": "forge:fluid"
  },
  "variants": {
    "your_fluid_type": [{
       "custom": { "fluid": "your_fluid_name" }
    }]
  }
}

 

I'm guessing it's something to do with the use of the "custom" tag, but maybe someone very knowledgeable about the forge blockstates format can explain fully.

Hey, look at that, it actually works! Thank you so much!

Seems like the simplest mistakes can lead to the most elusive problems.

Posted (edited)

Glad to help! Json can be a nightmare for small and inexplicable bugs. D:

 

I just dug through the ForgeBlockStateV1 code to understand why this happens. It's not specifically to do with the "custom" tag, it's just the way that forge identifies fully-defined variants. The way forge recognises a partially-defined variant (one where the properties will be combined with the properties from all other variants) is that the first element inside the variant is a json object (a tag followed by curly brackets). So the variant "property_name" is recognised as partially defined because the first element inside it is "one_value": { }, a json object:

"variants": {
    "property_name": {
     	"one_value": {
             // submodels and whatnot 
        },
        "another_value": {
            // submodels and whatnot 
        }
    }
}

 

And a fully-defined variant which starts with, say, a "model" tag will be recognised because the first element inside it is not a json object (it's a json primitive, a tag and one string):

"variants": {
    "full_variant": {
     	"model": "modid:modelname" 
    }
}

 

But, in a case like a fluid blockstates file, you might want to make a fully-defined variant (one that shouldn't be combined with other properties) where the first tag inside it happens to be a json object, like the "custom" tag:

"variants": {
    "fluid_variant": {
     	"custom": {
            // etc
        }
    }
}

 

So forge gets confused and thinks this is a property variant like the first example, and can't find it properly when it's needed. But (other than making sure the first element in the variant is an object, like by putting the "model" tag first inside every one), this check will be overriden if the variant is a json array (a tag followed by square brackets):

"variants": {
    "fluid_variant": [{
     	"custom": {
            // etc
        }
    }]
}

 

Sorry for the infodump, I got a bit focused on working this out because I've always been irritated by not understanding forge blockstates. :D I've seen advice to "use an array for fully-defined variants" but never quite understood why that was or how exactly it's defined.

 

 

Edited by Jay Avery
  • Like 1
Posted
1 hour ago, Alpvax said:

@Jay Avery  Really helpful and fully descriptive post. Could you update the documentation with this information. (Doc repository here).

I've never contributed to something on github before and I'm a bit unsure of what to do. Plus there's an open pull request for a big overhaul of the models and blockstates documentation so my small addition will probably get in the way?

Posted (edited)

I have asked the people working on the PR to integrate the information you posted.

 

In order to contribute, you need to create a copy (fork) of the repository, make the changes, and then open a PR between the 2 repositories.

Edited by Alpvax
Posted
2 hours ago, Alpvax said:

I have asked the people working on the PR to integrate the information you posted.

 

In order to contribute, you need to create a copy (fork) of the repository, make the changes, and then open a PR between the 2 repositories.

Thank you! :)

Posted

I'm having one other issue with my mod. I can't seem to get the universal bucket system to work. The link to my GitHub page is up above, Xechon added it.


The issue I'm having is that I'm trying to add a shapeless recipe that takes four items (three Drops of Mercury, which are from my mod, and an empty bucket) and returns a bucket that's full of liquid mercury. As it currently stands, it creates a pink and black square in the crafting menu, and the moment I mouse over it, it crashes the game due to a null pointer exception. 

Here's a crash report from it: https://pastebin.com/6LyMM573

 

The recipe is in my init event in my Main class.

Posted

That's definitely a step in the right direction. However, the item doesn't have any texture. It's still a pink and black square.

 

Slightly unrelated, but I also have no idea how to get my fluid to have proper liquid physics. It has no collision with entities, they walk right through it like air.

Posted (edited)

I don't know anything about the universal bucket textures, I'm afraid.

 

The fluids thing though - unfortunately forge fluids don't do anything with collisions. So if you want to e.g. make entities slow down in the fluid, you'll have to manually implement something. I have a very simple version here, overriding onEntityCollidedWithBlock to reduce the entity's horizontal motion by a fixed amount.

Edited by Jay Avery
  • Like 1
Posted
23 hours ago, Jay Avery said:

I don't know anything about the universal bucket textures, I'm afraid.

 

The fluids thing though - unfortunately forge fluids don't do anything with collisions. So if you want to e.g. make entities slow down in the fluid, you'll have to manually implement something. I have a very simple version here, overriding onEntityCollidedWithBlock to reduce the entity's horizontal motion by a fixed amount.

Awesome, thank you! I knew it had to be something with that particular method; I just couldn't quite figure out what it was.

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

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

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