Jump to content
  • Home
  • Files
  • Docs
Topics
  • All Content

  • This Topic
  • This Forum

  • Advanced Search
  • Existing user? Sign In  

    Sign In



    • Not recommended on shared computers


    • Forgot your password?

  • Sign Up
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.16.4] Change Texture onBlockActivated
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 1
BentiGorlich

[1.16.4] Change Texture onBlockActivated

By BentiGorlich, Thursday at 03:41 PM in Modder Support

  • Reply to this topic
  • Start new topic

Recommended Posts

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Thursday at 03:41 PM

Hallo Modders,

 

I want to have my Block change the texture to the texture of the block it is right clicked with. I honestly have no idea how this would be done other than override the `onBlockActivated` method.

Any idea how this could be done? It would be helpful if you could name a mod on 1.16 that does this in some regard, too.

 

Thanks in advance :)

 

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Thursday at 03:49 PM

Make two different blocks or a Boolean block state property. Then use onBlockActivated to switch between the two. You might want to look at the fence gate, which switches between open and closed.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Thursday at 03:58 PM

Ok i was not clear enough. I want it to be able to use any texture of any block on this. So if i right click it with oak planks it becomes an oak plank block (texture wise), if i right click it with stone it becomes stone and so on.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Thursday at 04:07 PM

You will need to do the following:

  1. Make a TileEntity and store the "mimiced" block state there. This is firstly not trivial, because the ItemStack => "block it would place" conversion is not trivial.
  2. Ensure this data is synced to the client.
  3. Override getModelData in your tile entity and return a data that contains the current block state.
  4. Call requestModelDataUpdate on the client on your TileEntity whenever the contained block state changes (a good place is onDataPacket, after the server has told the client the new block state).
  5. Make a custom model loader, which creates a special model that will mimic whatever blockstate your tile entity currently contains - it knows which block state it is based on the model data from step 3.
  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Thursday at 04:10 PM

Ok tanks, that is very helpful.
I will try that later on. But I do have one question already: where do I get the texture I have to render from, or is it contained in the BlockState and I dont really have to worry about that?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Thursday at 04:14 PM

You don't use the texture. You need to use the model that the contained block state uses (it may not be a cube, it may not even have a texture).

You can use BlockRendererDispatcher#getModelForState to get the model for a block state.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Thursday at 04:23 PM

It would be ok if there was the limitation that it could only look like other cubes and not like a torch for example. Thats why I thought, that shouldn't be that hard, just replace the texture from it with the texture from the right clicked block.

Override getModelData in your tile entity and return a data that contains the current block state.

how do I get an IModelData object from a BlockState? BlockRendererDispatcher#getModelForState is not static, how would I get an instance of that?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Thursday at 06:12 PM
1 hour ago, BentiGorlich said:

Thats why I thought, that shouldn't be that hard, just replace the texture from it with the texture from the right clicked block.

It's not trivial to determine if a model is a cube. It's also not trivial to get the texture from a model.

 

1 hour ago, BentiGorlich said:

how do I get an IModelData object from a BlockState?

Implement IModelData and add a field to your class that can store the BlockState.

 

1 hour ago, BentiGorlich said:

BlockRendererDispatcher#getModelForState is not static, how would I get an instance of that?

Minecraft#getBlockRendererDispatcher. Please try to use your IDE ;)

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Thursday at 06:58 PM
43 minutes ago, diesieben07 said:

Minecraft#getBlockRendererDispatcher. Please try to use your IDE

Yeah you were right, I could have found that by mysqlf, sorry.
 

 

43 minutes ago, diesieben07 said:

Implement IModelData and add a field to your class that can store the BlockState

Done

 

2 hours ago, diesieben07 said:

Ensure this data is synced to the client.

I don't know how to do that. The only time i really synced something to a client was through a open gui call, how would i send something to sync that up in the `onBlockActivated` method?

 

2 hours ago, diesieben07 said:

Make a custom model loader, which creates a special model that will mimic whatever blockstate your tile entity currently contains - it knows which block state it is based on the model data from step 3.

Can you give me a class to refer to? I really don't know which class I would have to extend for that, nor where to register it

 

I really appreciate your help :)

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Thursday at 07:24 PM
24 minutes ago, BentiGorlich said:

I don't know how to do that. The only time i really synced something to a client was through a open gui call, how would i send something to sync that up in the `onBlockActivated` method?

https://mcforge.readthedocs.io/en/latest/tileentities/tileentity/#synchronizing-the-data-to-the-client

 

25 minutes ago, BentiGorlich said:

Can you give me a class to refer to? I really don't know which class I would have to extend for that, nor where to register it

IModelLoader. There are several implementations in Forge already which you could look at for reference.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Friday at 12:28 PM

So I started looking into it. Sadly forge only has examples with the bucket item that are helpful, so I could not get the gist of it.

 

I have these 2 classes now:

public class GatePlacerModelLoader implements IModelLoader<GatePlacerModelConfiguration> {

	public static GatePlacerModelLoader INSTANCE = new GatePlacerModelLoader();
	
	@Override
	public void onResourceManagerReload(IResourceManager resourceManager) {
		// TODO Auto-generated method stub
	}

	@Override
	public GatePlacerModelConfiguration read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
		// TODO Auto-generated method stub
		return null;
	}
}
public class GatePlacerModelConfiguration implements IModelGeometry<GatePlacerModelConfiguration> {

	@Override
	public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) {
		
		return null;
	}

	@Override
	public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) {
		// TODO Auto-generated method stub
		return null;
	}
}

And I register the loader like so:

public void init(FMLServerStartingEvent event) {
	ModelLoaderRegistry.registerLoader(new ResourceLocation(MODID, "gate_placer"), GatePlacerModelLoader.INSTANCE);
}

My problem is, that I couldn't find a reference to how these are called for rendering

- how to tell them which block they should render through my render model

- how do I get the blockstate of the mimiced block (I can't get the normal block state eigher...)

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Friday at 01:06 PM
32 minutes ago, BentiGorlich said:

 


public void init(FMLServerStartingEvent event) {
	ModelLoaderRegistry.registerLoader(new ResourceLocation(MODID, "gate_placer"), GatePlacerModelLoader.INSTANCE);
}

 

Use ModelRegistryEvent instead.

 

36 minutes ago, BentiGorlich said:

how to tell them which block they should render through my render model

In your model you need to delegate the methods (the most important one is probably just getQuads) to the other model. Which "other model" you use depends on the model data (it has the mimiced block state in it). By delegating to the other model here, your block will appear as if it had that other model.

 

37 minutes ago, BentiGorlich said:

how do I get the blockstate of the mimiced block (I can't get the normal block state eigher...)

Its given to you as the IModelData in your IBakedModel. This is the same model data you returned from your tile entity.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Friday at 01:17 PM
6 minutes ago, diesieben07 said:

Use ModelRegistryEvent instead.

Done

6 minutes ago, diesieben07 said:
43 minutes ago, BentiGorlich said:

how to tell them which block they should render through my render model

In your model you need to delegate the methods (the most important one is probably just getQuads) to the other model. Which "other model" you use depends on the model data (it has the mimiced block state in it). By delegating to the other model here, your block will appear as if it had that other model.

Which class do you mean with "model"? I do not have a method called `getQuads()` in the GatePlacerModelLoader class, the GatePlacerModelConfiguration class, the GatePlacerBlock class, or the GatePlacerTileEntity class. So do I have to make another class class GatePlacerModel? and where would I register it, so it renders my block?

 

9 minutes ago, diesieben07 said:
47 minutes ago, BentiGorlich said:

how do I get the blockstate of the mimiced block (I can't get the normal block state eigher...)

Its given to you as the IModelData in your IBakedModel. This is the same model data you returned from your tile entity.

In the GatePlacerModelConfiguration class I have to return a `IBakedModel` in the bake method. How do I build it?
And where would I have a method for using the baked model?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Friday at 01:37 PM
18 minutes ago, BentiGorlich said:

Which class do you mean with "model"? I do not have a method called `getQuads()` in the GatePlacerModelLoader class, the GatePlacerModelConfiguration class, the GatePlacerBlock class, or the GatePlacerTileEntity class. So do I have to make another class class GatePlacerModel? and where would I register it, so it renders my block?

In your IModelGeometry implementation you need to return an IBakedModel in bake(). This IBakedModel has getQuads.

 

19 minutes ago, BentiGorlich said:

In the GatePlacerModelConfiguration class I have to return a `IBakedModel` in the bake method. How do I build it?

You make a class that implements IBakedModel.

 

19 minutes ago, BentiGorlich said:

And where would I have a method for using the baked model?

Not sure what you mean by this.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Friday at 01:43 PM
6 minutes ago, diesieben07 said:

You make a class that implements IBakedModel.

Ok, so that was the part I missed before. Thank you, I will try that

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Friday at 02:27 PM

Ok so I have run into a problem again. How do I get the model of the mimiced block from its blockstate?

50 minutes ago, diesieben07 said:

Not sure what you mean by this.

To clarify: where do I register my created model so that my block is rendered by it?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted Friday at 02:43 PM
12 minutes ago, BentiGorlich said:

How do I get the model of the mimiced block from its blockstate?

22 hours ago, diesieben07 said:

You can use BlockRendererDispatcher#getModelForState to get the model for a block state.

 

13 minutes ago, BentiGorlich said:

where do I register my created model so that my block is rendered by it?

You make a normal JSON model for your block like you would with a "normal" block model. Then in that JSON model you specify "loader": "yourmod:yourloader". This will then load that JSON model using your loader (IModelLoader#read) and use the result as the model for your block.

You can even configure what your loader does by reading additional data from the JSON object - but that is not necessary, just the "loader" property will already make it so your loader is used.

  • Quote

Share this post


Link to post
Share on other sites

BentiGorlich    0

BentiGorlich

BentiGorlich    0

  • Tree Puncher
  • BentiGorlich
  • Members
  • 0
  • 29 posts
Posted Friday at 08:11 PM

I have the problem, that nothing is happening. I have the loader and the model in the blockstate.json:
(if I remove the model property it just renders as the default black/pink block)

{
    "variants": {
        "": { 
            "loader": "gates:gate_placer_loader",
            "model": "gates:block/gate_placer"
        }
    }
}

But my GatePlacerModel class is never called.

ModelLoader:

public class GatePlacerModelLoader implements IModelLoader<GatePlacerModelConfiguration> {

	public static GatePlacerModelLoader INSTANCE = new GatePlacerModelLoader();
	
	@Override
	public void onResourceManagerReload(IResourceManager resourceManager) {
		// TODO Auto-generated method stub
	}

	@Override
	public GatePlacerModelConfiguration read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
		return new GatePlacerModelConfiguration();
	}
}

ModelConfiguration:

public class GatePlacerModelConfiguration implements IModelGeometry<GatePlacerModelConfiguration> {

	@Override
	public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) {
		return new GatePlacerModel(overrides);
	}

	@Override
	public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) {
		Set<RenderMaterial> texs = Sets.newHashSet();

        if (owner.isTexturePresent("base")) texs.add(owner.resolveTexture("base"));
        if (owner.isTexturePresent("all")) texs.add(owner.resolveTexture("all"));

        return texs;
	}
}

Model:

public class GatePlacerModel extends BakedModel {

	public GatePlacerModel(ItemOverrideList overrides) {
		super(false, false, false, null, overrides, null, null);
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData extraData) {
		if(extraData.hasProperty(GatePlacerTileEntity.MIMICED_BLOCKSTATE_PROPERTY)) {
			BlockState mimiced = extraData.getData(GatePlacerTileEntity.MIMICED_BLOCKSTATE_PROPERTY);
			IBakedModel mimicedModel = Minecraft.getInstance().getBlockRendererDispatcher().getModelForState(mimiced);
			return mimicedModel.getQuads(mimiced, side, rand, extraData);
		} else {
			return super.getQuads(state, side, rand, extraData);
		}
	}
}

Inside of my block i have this method:

	@Override
	public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
		ItemStack activeStack = player.getHeldItem(handIn);
		if(activeStack.getItem() instanceof BlockItem) {
			Block block = ((BlockItem)activeStack.getItem()).getBlock();
			((GatePlacerTileEntity)worldIn.getTileEntity(pos)).setMimicedBlockState(block.getDefaultState());
			// notify for block update, so the new mimiced block is synced in the tileentity class
			worldIn.notifyBlockUpdate(pos, state, state.with(MIMICED, Boolean.valueOf(true)), 2);
			return ActionResultType.SUCCESS;
		}
		return ActionResultType.FAIL;
	}

Am I doing something wrong?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7586

diesieben07

diesieben07    7586

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7586
  • 54922 posts
Posted 19 hours ago
13 hours ago, BentiGorlich said:

I have the problem, that nothing is happening. I have the loader and the model in the blockstate.json:
(if I remove the model property it just renders as the default black/pink block)


{
    "variants": {
        "": { 
            "loader": "gates:gate_placer_loader",
            "model": "gates:block/gate_placer"
        }
    }
}

But my GatePlacerModel class is never called.

This looks like a block state file, not a model file. The "loader" property needs to be in your model JSON.

  • Quote

Share this post


Link to post
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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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.

    • Insert image from URL
×
  • Desktop
  • Tablet
  • Phone
Sign in to follow this  
Followers 1
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • metword
      [1.16.4] Config file will not update.

      By metword · Posted 48 minutes ago

      The logger is just to help me read more clearly what is going on in the code.   I am still confused how I should connect the two.
    • StealthyNoodle
      [SOLVED] How to register WallOrFloorItem / Torch

      By StealthyNoodle · Posted 1 hour ago

      Fantastic - That would take me days to figure out! Got it all up and running now. Thanks a lot, man!     I'll keep this in mind too
    • ChampionAsh5357
      [1.16.4] Config file will not update.

      By ChampionAsh5357 · Posted 1 hour ago

      It seems your testing if the value changed using the logger, which will always be the default value when first initialized.   This is not to mention that the entirety of the code is reaching across sides and still trying to force load the config.
    • metword
      [1.16.4] Config file will not update.

      By metword · Posted 2 hours ago

      https://github.com/metword/TextReaderMod
    • ChampionAsh5357
      [1.16.4] Config file will not update.

      By ChampionAsh5357 · Posted 2 hours ago

      Please link your repository then. I'm questioning a few things regarding that TextConfig class and context surrounding what you are using on the client and server configuration.
  • Topics

    • metword
      15
      [1.16.4] Config file will not update.

      By metword
      Started Wednesday at 04:20 PM

    • StealthyNoodle
      6
      [SOLVED] How to register WallOrFloorItem / Torch

      By StealthyNoodle
      Started Friday at 03:39 AM

    • JeffMan
      3
      [1.15] replacing chunks

      By JeffMan
      Started 9 hours ago

    • AurenX
      0
      [1.16.4] Generation Help

      By AurenX
      Started 3 hours ago

    • gibbyj
      3
      Help using Minecraft Forge on Manjaro Linux

      By gibbyj
      Started 7 hours ago

  • Who's Online (See full list)

    • DaemonUmbra
    • coalbricks
    • fewf
    • StealthyNoodle
    • LexManos
    • sarkozi
    • thabeez78
    • Dollar98PlusTax
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.16.4] Change Texture onBlockActivated
  • Theme

Copyright © 2019 ForgeDevelopment LLC · Ads by Longitude Ads LLC Powered by Invision Community