Jump to content

[1.10.2] Blocks that Re-Texture when clicked depending on what the player is holding


Recommended Posts

Posted (edited)

I'm recreating the mod Engineer's Toolbox for my personal use and in this mod you're able to configure a single block's sides for different ports or for the block to be used as different machines.

So for example I could choose what side power got inputed in by right clicking with a power input socket on the side I wanted.

Since this single block could have many different configurations depending on how many sockets I implement from the mod or if I create more I don't think I can create a massive list of blockstates.

 

So my question is what other options do I have for re-rendering a block's side through the block's onBlockActivated() method, AND are there any good tutorials for those methods that you know of.

Edited by 15Cyndaquil
Posted

This would be covered by IBlockStates pretty well.

 

All you have to do is properly define your blockstate json.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

I've gotten my block to now change dynamically with 6 different properties, thank you for sugesting IBlockStates Draco, and while i am able to save each state to a TileEntity as well as able to change the state through the same TileEntity .

 

I have the new problem of when i try to load the states through the TileEntity using the Overriden method readFromNBT() in the TileEntity it loads the default values i set for the states in the TileEntity when I have a non-null world instead of the values saved from the previous session..

Posted

Block code:

 

package com.cynda.cyndas_toolbox.block;

import com.cynda.cyndas_toolbox.CyndasToolbox;
import com.cynda.cyndas_toolbox.EnumHandler.SocketBlockSide;
import com.cynda.cyndas_toolbox.tiles.Test;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;

public class BlockSocket extends Block implements ITileEntityProvider{

    final static PropertyEnum<SocketBlockSide> EAST = PropertyEnum.create("east", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> WEST = PropertyEnum.create("west", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> NORTH = PropertyEnum.create("north", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> SOUTH = PropertyEnum.create("south", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> UP = PropertyEnum.create("up", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> DOWN = PropertyEnum.create("down", SocketBlockSide.class);

    

    public BlockSocket(String unlocalizedName){
        super(Material.IRON);
        setUnlocalizedName(unlocalizedName);
        setCreativeTab(CyndasToolbox.tabBlocks);



        setDefaultState(getBlockState().getBaseState().withProperty(EAST, SocketBlockSide.BLANK));
        setDefaultState(getBlockState().getBaseState().withProperty(WEST, SocketBlockSide.BLANK));
        setDefaultState(getBlockState().getBaseState().withProperty(NORTH, SocketBlockSide.BLANK));
        setDefaultState(getBlockState().getBaseState().withProperty(SOUTH, SocketBlockSide.BLANK));
        setDefaultState(getBlockState().getBaseState().withProperty(UP, SocketBlockSide.BLANK));
        setDefaultState(getBlockState().getBaseState().withProperty(DOWN, SocketBlockSide.BLANK));
    }


    @SideOnly(Side.CLIENT)
    @Override
    public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, @Nullable ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ) {

        if(!worldIn.isRemote) {
//            worldIn.markBlocksDirtyVertical(pos.getX(), pos.getZ(), pos.getX(), pos.getZ());

            TileEntity te = worldIn.getTileEntity(pos);
            if (te != null && te instanceof Test) {
                Test tileTest = (Test) te;
                state = setFaceRandom(state, getSide(side), playerIn, tileTest, side);
                worldIn.setBlockState(pos, state);
                tileTest.markDirty();
                if (playerIn.isSneaking()) {
                    playerIn.addChatMessage(new TextComponentString("Clicks " + tileTest.getClicks()));
                } else {
                    tileTest.setClicks(tileTest.getClicks() + 1);
                    tileTest.markDirty();
                }
            }
        }
        return true;
    }

    private IBlockState setFaceRandom(IBlockState state, PropertyEnum side, EntityPlayer playerIn, Test tileTest, EnumFacing sideFace){
        if(playerIn.getHeldItemMainhand()==null){
            state = state.withProperty(side, SocketBlockSide.INPUT_POWER);
            tileTest.setSide(sideFace, "input_power");
            System.out.println("INPUT");
        }else {
            state = state.withProperty(side, SocketBlockSide.BLANK);
            tileTest.setSide(sideFace, "blank");
            System.out.println("BLANK");
        }
        return state;
    }

    private PropertyEnum getSide(EnumFacing side){
        PropertyEnum enumSide = EAST;
        switch (side){
            case EAST:
                enumSide = EAST;
                break;
            case WEST:
                enumSide = WEST;
                break;
            case NORTH:
                enumSide = NORTH;
                break;
            case SOUTH:
                enumSide = SOUTH;
                break;
            case UP:
                enumSide = UP;
                break;
            case DOWN:
                enumSide = DOWN;
                break;
        }
        return enumSide;
    }

    public void setEast(SocketBlockSide value){

        setDefaultState(getBlockState().getBaseState().withProperty(EAST, value));
    }
    @Override
    public IBlockState getStateFromMeta(int meta) {return this.getDefaultState();}
    @Override
    public int getMetaFromState(IBlockState state) {return 0;}

    //Methods for ITileEntityProvider
    @Override
    public TileEntity createNewTileEntity(World worldIn, int meta) { return new Test(); }

    @Override
    protected BlockStateContainer createBlockState() {
        return new BlockStateContainer(this, EAST, WEST, NORTH, SOUTH, UP, DOWN);
    }


    public PropertyEnum<SocketBlockSide> getEAST() {return EAST;}
    public PropertyEnum<SocketBlockSide> getWEST() {return WEST;}
    public PropertyEnum<SocketBlockSide> getNORTH() {return NORTH;}
    public PropertyEnum<SocketBlockSide> getSOUTH() {return SOUTH;}
    public PropertyEnum<SocketBlockSide> getUP() {return UP;}
    public PropertyEnum<SocketBlockSide> getDOWN() {return DOWN;}
}

 

TileEntity code:

 

package com.cynda.cyndas_toolbox.tiles;

import akka.io.Tcp;
import com.cynda.cyndas_toolbox.EnumHandler.SocketBlockSide;
import com.cynda.cyndas_toolbox.block.BlockSocket;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class Test extends TileEntity{

    private int clicks = 0;
    private int east = 0;

    private IntegerProperty eastProptery = new SimpleIntegerProperty(east);
//    private String west = "blank";
//    private String north = "blank";
//    private String south = "blank";
//    private String up = "blank";
//    private String down = "blank";

    private World world;


    final static PropertyEnum<SocketBlockSide> EAST = PropertyEnum.create("east", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> WEST = PropertyEnum.create("west", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> NORTH = PropertyEnum.create("north", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> SOUTH = PropertyEnum.create("south", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> UP = PropertyEnum.create("up", SocketBlockSide.class);
    final static PropertyEnum<SocketBlockSide> DOWN = PropertyEnum.create("down", SocketBlockSide.class);

    public Test(){
        eastProptery.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable e) {
                boolean firstLoad = true;
                if(getWorld()==null){
                    System.out.println(e + " East + null");
//                        int x = Integer.valueOf(e.toString().substring(e.toString().length() - 2, e.toString().length() - 1)) - 1;
//                        System.out.println(x);
//                        eastProptery.setValue(x);
                }else {
                    System.out.println(e + " East");
                    final IBlockState state = getWorld().getBlockState(getPos());
//
////            EAST = ((BlockSocket) getBlockType()).getEAST();
////            WEST = ((BlockSocket) getBlockType()).getWEST();
////            NORTH = ((BlockSocket) getBlockType()).getNORTH();
////            SOUTH = ((BlockSocket) getBlockType()).getSOUTH();
////            UP = ((BlockSocket) getBlockType()).getUP();
////            DOWN = ((BlockSocket) getBlockType()).getDOWN();
//
                    setState(state);
                }
            }
        });
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        compound.setInteger("Clicks", clicks);
        compound.setInteger("East", east);
//        compound.setString("West", west);
//        compound.setString("North", north);
//        compound.setString("South", south);
//        compound.setString("Up", up);
//        compound.setString("Down", down);
        markDirty();
        super.writeToNBT(compound);

        return compound;
    }




    @Override
    public void readFromNBT(NBTTagCompound compound){
        System.out.println("Hello NBTReadNOW");
        super.readFromNBT(compound);
        if(getWorld()==null){
            clicks = compound.getInteger("Clicks");
            east = compound.getInteger("East");
            eastProptery.setValue(east);
            System.out.println(compound.getInteger("East")+" Read "+compound.getInteger("Clicks"));
        }
        System.out.println(getWorld());
        if(getWorld()!=null) {
            System.out.println(eastProptery.intValue() +" East Value");
            final IBlockState state = getWorld().getBlockState(getPos());
            setState(state);

        }
    }



    public int getClicks() {return clicks; }

    public void setClicks(int clicks) { this.clicks = clicks; markDirty();}
    public void setEast(int east){this.east = east; eastProptery.setValue(east);}

    public void setSide(EnumFacing side, String value) {
        switch (side){
            case EAST:
                east = SocketBlockSide.getName(value).getID();
                eastProptery.setValue(east);
//                System.out.println(eastProptery);
                markDirty();
                break;
            case WEST:
//                west = value;
                markDirty();
                break;
            case NORTH:
//                north = value;
                markDirty();
                break;
            case SOUTH:
//                south = value;
                markDirty();
                break;
            case UP:
//                up = value;
                markDirty();
                break;
            case DOWN:
//                down = value;
                markDirty();
                break;
        }

    }


    public void setState(IBlockState state){
        System.out.println(east+" Set State");
        state = state.withProperty(EAST, SocketBlockSide.values()[eastProptery.intValue()]);
//        state = state.withProperty(WEST, SocketBlockSide.getName(west));
//        state = state.withProperty(NORTH, SocketBlockSide.getName(north));
//        state = state.withProperty(SOUTH, SocketBlockSide.getName(south));
//        state = state.withProperty(UP, SocketBlockSide.getName(up));
//        state = state.withProperty(DOWN, SocketBlockSide.getName(down));
        getWorld().setBlockState(pos, state);
        System.out.println("set BlockState"+getPos().toString()+state.toString());
    }


    /**
     * This controls whether the tile entity gets replaced whenever the block state
     * is changed. Normally only want this when block actually is replaced.
     */
    @Override
    public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)
    {
        return (oldState.getBlock() != newState.getBlock());
    }


}
Posted

So I think I know what the issue is. My theory is that there are two tileEntities. one on the server and one on the client. when the tileEntities are created the server side one doesn't initially have a world object so I cant set a block's state in the readFromNBT() method from the server side, and when the client creates its tileEntities it doesnt have the nbt Data the server has so it creates a default one.

 

I've tried to sync them by requesting the information from the server when the client loads it's tileEntities but from what i can see it doesnt get the data quick enough to be useful for when the game renders in.

 

Does anyone know either another way to save the blockstate that would be more reliable or a way to get the nbt data to sync before the game loads.

Posted

You are essentially correct on all points.

 

Have you overridden these three methods? One of them is explicitly for the purpose of telling the client what the nbt data was when the TE was loaded from disk.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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

    • Im trying to build my mod using shade since i use the luaj library however i keep getting this error Reason: Task ':reobfJar' uses this output of task ':shadowJar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. So i try adding reobfJar.dependsOn shadowJar  Could not get unknown property 'reobfJar' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. my gradle file plugins { id 'eclipse' id 'idea' id 'maven-publish' id 'net.minecraftforge.gradle' version '[6.0,6.2)' id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.spongepowered.mixin' version '0.7.+' } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' apply plugin: 'com.github.johnrengelman.shadow' version = mod_version group = mod_group_id base { archivesName = mod_id } // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) //jarJar.enable() println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { mappings channel: mapping_channel, version: mapping_version copyIdeResources = true runs { configureEach { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' arg "-mixin.config=derp.mixin.json" mods { "${mod_id}" { source sourceSets.main } } } client { // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. property 'forge.enabledGameTestNamespaces', mod_id } server { property 'forge.enabledGameTestNamespaces', mod_id args '--nogui' } gameTestServer { property 'forge.enabledGameTestNamespaces', mod_id } data { workingDirectory project.file('run-data') args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } sourceSets.main.resources { srcDir 'src/generated/resources' } repositories { flatDir { dirs './libs' } maven { url = "https://jitpack.io" } } configurations { shade implementation.extendsFrom shade } dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" implementation 'org.luaj:luaj-jse-3.0.2' implementation fg.deobf("com.github.Virtuoel:Pehkui:${pehkui_version}") annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' minecraftLibrary 'luaj:luaj-jse:3.0.2' shade 'luaj:luaj-jse:3.0.2' } // Example for how to get properties into the manifest for reading at runtime. tasks.named('jar', Jar).configure { manifest { attributes([ 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors, 'Specification-Version' : '1', // We are version 1 of ourselves 'Implementation-Title' : project.name, 'Implementation-Version' : project.jar.archiveVersion, 'Implementation-Vendor' : mod_authors, 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakOrder" : 0, "MixinConfigs" : "derp.mixin.json" ]) } rename 'mixin.refmap.json', 'derp.mixin-refmap.json' } shadowJar { archiveClassifier = '' configurations = [project.configurations.shade] finalizedBy 'reobfShadowJar' } assemble.dependsOn shadowJar reobf { re shadowJar {} } publishing { publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file://${project.projectDir}/mcmodsrepo" } } }  
    • All versions of Minecraft Forge suddenly black screen even without mods (tried reinstalling original Minecraft, Java, updating drivers doesn't work)
    • When i join minecraft all ok, when i join world all working fine, but when i open indentity menu, i get this The game crashed whilst unexpected error Error: java.lang.NullPointerException: Cannot invoke "top.ribs.scguns.common.Gun$Projectile.getDamage()" because "this.projectile" is null crash report here https://paste.ee/p/0vKaf
  • Topics

×
×
  • Create New...

Important Information

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