Jump to content

Jipthechip

Members
  • Posts

    28
  • Joined

  • Last visited

Everything posted by Jipthechip

  1. I'm trying to use Geckolib to have a block animation play when the block is right clicked, however it isn't working properly. When I right click the block the animation will play once, and then any subsequent times I right click, nothing happens. Here's my Block class: public class MagicChurnerBlock extends BlockWithEntity { protected MagicChurnerBlock(Settings settings) { super(settings); } @Nullable @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new MagicChurner(pos, state); } @Nullable @Override public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) { return checkType(type, DiabolismEntities.MAGIC_CHURNER_BLOCKENTITY, MagicChurner::ticker); } @Override public BlockRenderType getRenderType(BlockState state) { return BlockRenderType.ENTITYBLOCK_ANIMATED; } @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { MagicChurner magicChurner = (MagicChurner) world.getBlockEntity(pos); if(magicChurner != null && world.isClient){ magicChurner.turn(); } return ActionResult.SUCCESS; } } And my Block Entity Class: public class MagicChurner extends AbstractFluidContainer implements IAnimatable { private AnimationFactory factory = new InstancedAnimationFactory(this); private boolean hasBeenTurned =false; public MagicChurner(BlockPos pos, BlockState state) { super(DiabolismEntities.MAGIC_CHURNER_BLOCKENTITY, pos, state, 1000); } @Override public void registerControllers(AnimationData animationData) { animationData.addAnimationController(new AnimationController<MagicChurner>(this, "controller", 0, this::predicate)); } private <E extends IAnimatable>PlayState predicate(AnimationEvent<E> event){ if(hasBeenTurned) { event.getController().setAnimation(new AnimationBuilder().addAnimation("magic_churner_turn", (ILoopType) ILoopType.EDefaultLoopTypes.PLAY_ONCE)); hasBeenTurned = false; } return PlayState.CONTINUE; } @Override public AnimationFactory getFactory() { return this.factory; } public static void ticker(World world, BlockPos pos, BlockState state, MagicChurner be) { be.tick(world, pos, state); } private void tick(World world, BlockPos pos, BlockState state) { } public void turn(){ this.hasBeenTurned = true; }
  2. During testing I noticed it usually wasn't being called when I loaded in my TileEntity, so I'm assuming the client has to tell the server it needs the data, then the server calls read() and sends the data to the client?
  3. Ohhh ok that makes a lot of sense now. I didn't think I'd need to learn about packets so soon, but I guess I have no choice now. But there's one thing I'm still confused about. So I'm guessing write() is a function that is called serverside to save the NBT data whenever the server decides to save the chunk that the TileEntity is in. But when is read() called? When I was testing, it was called at seemingly random times and I'm still confused where it fits in.
  4. So you're saying that the NBT data is being written and the server has it, but the client for some reason isn't receiving it when the chunk is loaded? If so, how do I make sure that the client and server are synchronized?
  5. My bad, I can tell it's no longer there because I have an IBlockColor class setting the color of one of the submodels of the TileEntity, and the color depends on data within my custom TileEntity class. When I reload the chunk, the color goes back to its default blue and the TileEntity accepts 4 ingredients again even though it should be full. Also here is my custom IBlockColor class in case this helps: package com.jipthechip.fermentationmod.Blocks; import com.jipthechip.fermentationmod.Entities.MasherBowlTileEntity; import net.minecraft.block.BlockState; import net.minecraft.block.material.MaterialColor; import net.minecraft.client.renderer.color.IBlockColor; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockDisplayReader; import javax.annotation.Nullable; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.world.World; import static com.jipthechip.fermentationmod.Entities.MasherBowlTileEntity.FoodType; public class MasherWaterColor implements IBlockColor { private final Map<FoodType, Integer> foodColors = Stream.of(new Object[][] { {FoodType.apple, 0xffffe063}, {FoodType.baked_potato, 0xfffff8ad}, {FoodType.beetroot, 0xffa4272b}, {FoodType.bread, 0xffe8d697}, {FoodType.carrot, 0xffff8e09}, {FoodType.chorus_fruit, 0xff8E678D}, {FoodType.dried_kelp, 0xff3C3324}, {FoodType.kelp, 0xff5C8332}, {FoodType.honey_bottle, 0xffFFD32D}, {FoodType.melon_slice, 0xffBF3123}, {FoodType.potato, 0xfffff8ad}, {FoodType.poisonous_potato, 0xffefffad}, {FoodType.pumpkin, 0xffE38A1D}, {FoodType.sweet_berries, 0xffDF467E}, {FoodType.nothing, MaterialColor.WATER.colorValue} }).collect(Collectors.toMap(data -> (FoodType) data[0], data -> (Integer) data[1])); @Override public int getColor(BlockState state, @Nullable IBlockDisplayReader blockDisplayReader, @Nullable BlockPos pos, int tintIndex) { assert blockDisplayReader != null; assert pos != null; MasherBowlTileEntity tileEntity = (MasherBowlTileEntity) blockDisplayReader.getTileEntity(pos); assert tileEntity != null; // mix the colors of the 4 ingredients together int ingredients = mixColors(1, foodColors.get(tileEntity.getIngredient(0)), mixColors(1, foodColors.get(tileEntity.getIngredient(1)), mixColors(1, foodColors.get(tileEntity.getIngredient(2)), foodColors.get(tileEntity.getIngredient(3))))); return mixColors(10-state.get(MasherBowlBlock.STIR_PROGRESS), MaterialColor.WATER.colorValue, ingredients); } private int mixColors(int weight, int color1, int color2){ if(weight == 0){ return color2; } int color1_a = (color1 & 0xff000000) >> 24; int color1_r = (color1 & 0x00ff0000) >> 16; int color1_g = (color1 & 0x0000ff00) >> 8; int color1_b = color1 & 0x000000ff; int color2_a = (color2 & 0xff000000) >> 24; int color2_r = (color2 & 0x00ff0000) >> 16; int color2_g = (color2 & 0x0000ff00) >> 8; int color2_b = color2 & 0x000000ff; int result_a = color2_a; int result_r = color2_r; int result_g = color2_g; int result_b = color2_b; for(int i = 0; i < weight; i++){ result_a = (result_a + color1_a)/2; result_r = (result_r + color1_r)/2; result_g = (result_g + color1_g)/2; result_b = (result_b + color1_b)/2; } result_a = result_a << 24; result_r = result_r << 16; result_g = result_g << 8; return result_a + result_r + result_g + result_b; } }
  6. I'm trying to save the data of a custom TileEntity, but it doesn't seem to be working properly because after unloading and reloading the chunk, the data is no longer there. Here is my TileEntity class: package com.jipthechip.fermentationmod.Entities; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IStringSerializable; import java.util.Arrays; @MethodsReturnNonnullByDefault public class MasherBowlTileEntity extends TileEntity { public enum FoodType implements IStringSerializable { apple, baked_potato, beetroot, bread, carrot, chorus_fruit, dried_kelp, kelp, honey_bottle, melon_slice, potato, poisonous_potato, pumpkin, sweet_berries, nothing; @Override public String getString() { return this.name(); } } private FoodType[] ingredients = new FoodType[4]; public MasherBowlTileEntity(){ super(TileEntitiesList.masher_bowl); clearFoods(); } @Override public void read(BlockState state, CompoundNBT compound) { super.read(state, compound); int [] arr = compound.getIntArray("foodarr"); if(arr.length == 0) System.out.println("no ingredients read!"); else System.out.print("reading ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n"); for(int i = 0; i < arr.length; i++){ ingredients[i] = FoodType.values()[arr[i]]; } } private int[] foodToIntArray(FoodType[] arr){ int[] result = new int[arr.length]; for(int i = 0; i < arr.length; i++){ result[i] = arr[i].ordinal(); } return result; } @Override public CompoundNBT write(CompoundNBT compound) { super.write(compound); int [] arr = foodToIntArray(ingredients); compound.putIntArray("foodarr", arr); System.out.print("writing ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n"); return compound; } public boolean addFood(FoodType food){ for(int i = 0; i < ingredients.length; i++){ if(ingredients[i] == FoodType.nothing){ markDirty(); ingredients[i] = food; return true; } } return false; } public void clearFoods(){ markDirty(); Arrays.fill(ingredients, FoodType.nothing); } public FoodType getIngredient(int index) { return ingredients[index]; } } In order to have TileEntity data saved to the world, you use the read() and write() methods of the TileEntity class to read and write NBT's, correct? And when exactly are read() and write() called?
  7. My registration class: @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class RegisterBlocks { @SubscribeEvent public static void registerBlocks(final RegistryEvent.Register<Block> event){ event.getRegistry().registerAll( BlocksList.masher_bowl = new MasherBowlBlock(Block.Properties.create(Material.IRON)) .setRegistryName(new ResourceLocation(MOD_ID, "masher_bowl")) } @SubscribeEvent public static void registerTE(RegistryEvent.Register<TileEntityType<?>> event) { event.getRegistry().registerAll( TileEntitiesList.masher_bowl = TileEntityType.Builder.create(MasherBowlTileEntity::new, BlocksList.masher_bowl).build(null) .setRegistryName(MOD_ID, "masher_bowl") ); } } My Block class: public class MasherBowlBlock extends Block { public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING; public static final BooleanProperty CONTAINS_ROD = BooleanProperty.create("contains_rod"); public static final DirectionProperty ROD_FACING = DirectionProperty.create("rod_facing", Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); public static final BooleanProperty CONTAINS_WATER = BooleanProperty.create("contains_water"); public static final IntegerProperty STIR_PROGRESS = IntegerProperty.create("stir_progress", 0,10); public MasherBowlBlock(Properties properties) { super(properties.notSolid()); this.setDefaultState(this.getStateContainer().getBaseState() .with(FACING, Direction.NORTH) .with(CONTAINS_ROD, false) .with(ROD_FACING, Direction.NORTH) .with(CONTAINS_WATER, false) .with(STIR_PROGRESS, 0) ); } @Override public BlockState getStateForPlacement(BlockItemUseContext context){ return this.getDefaultState() .with(FACING, context.getPlacementHorizontalFacing().getOpposite()) .with(CONTAINS_ROD, false) .with(ROD_FACING, context.getPlacementHorizontalFacing().getOpposite()) .with(CONTAINS_WATER, false) .with(STIR_PROGRESS, 0); } @Override protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) { builder.add(FACING, CONTAINS_ROD, ROD_FACING, CONTAINS_WATER, STIR_PROGRESS); } @Override public boolean hasTileEntity(BlockState state) { return true; } @Nullable @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new MasherBowlTileEntity(); } @Override public BlockState rotate(BlockState state, Rotation rot) { return state.with(FACING, rot.rotate(state.get(FACING))); } @Override public BlockState mirror(BlockState state, Mirror mirrorIn) { return state.rotate(mirrorIn.toRotation(state.get(FACING))); } @Override public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { ItemStack heldItem = player.getHeldItem(handIn); String itemRegistryName = Objects.requireNonNull(heldItem.getItem().getRegistryName()).toString(); System.out.println(itemRegistryName); switch(itemRegistryName){ case MOD_ID+":masher_rod_item": if(!player.isCreative()) { heldItem.setCount(heldItem.getCount() - 1); } player.sendBreakAnimation(handIn); worldIn.setBlockState(pos, state.with(CONTAINS_ROD, true)); return ActionResultType.SUCCESS; case "minecraft:water_bucket": if(!state.get(CONTAINS_WATER)){ if(!player.isCreative()){ ItemStack bucket = new ItemStack(Items.BUCKET); player.setHeldItem(handIn, bucket); } worldIn.playSound(player, pos, SoundEvents.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 10.0f, 1.0f); worldIn.setBlockState(pos, state.with(CONTAINS_WATER, true)); return ActionResultType.SUCCESS; } break; case "minecraft:bucket": if(state.get(CONTAINS_WATER)){ if(!player.isCreative()){ ItemStack water_bucket = new ItemStack(Items.WATER_BUCKET); player.setHeldItem(handIn, water_bucket); } worldIn.playSound(player, pos, SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 10.0f, 1.0f); worldIn.setBlockState(pos, state.with(CONTAINS_WATER, false) .with(STIR_PROGRESS, 0)); return ActionResultType.SUCCESS; } break; } // check if the item is one of the valid foods String path = itemRegistryName.split(":")[1]; if(EnumUtils.isValidEnum(FoodType.class, path) && state.get(CONTAINS_WATER)) { FoodType food = EnumUtils.getEnum(FoodType.class, path); MasherBowlTileEntity tileEntity = (MasherBowlTileEntity)worldIn.getTileEntity(pos); assert tileEntity != null; if(tileEntity.addFood(food)) { return ActionResultType.SUCCESS; } } return ActionResultType.PASS; } } I also have 2 classes that store registered blocks and tile entities: public class TileEntitiesList { public static TileEntityType<?> masher_bowl; } public class BlocksList { public static Block masher_bowl; }
  8. Oh ok, that makes sense. I was just concerned because I noticed that it wasn't calling my write function before the chunk was unloaded, and then I'd reload the chunk and my data would be gone. But now I think this is simply due to the fact that my write function isn't properly writing data to the NBT, or I'm not properly reading somehow. I added the super call to my read and write and the problem persists. Looking at some other TileEntities, I assume you need to add the super call to TileEntity#read as well? I updated my code at the top. I could just remember to add new entries to the end, but if I'm gonna be adding a lot, which I may have to if I want to integrate with other mods, that might get messy. But it may be worth it because it's reading/writing less data.
  9. Here is my TileEntity class: import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IStringSerializable; import java.util.Arrays; public class MasherBowlTileEntity extends TileEntity { public enum FoodType implements IStringSerializable { apple, baked_potato, beetroot, bread, carrot, chorus_fruit, dried_kelp, kelp, honey_bottle, melon_slice, potato, poisonous_potato, pumpkin, sweet_berries, nothing; @Override public String getName() { return this.name(); } } private FoodType[] ingredients = new FoodType[4]; public MasherBowlTileEntity(){ super(TileEntitiesList.masher_bowl); clearFoods(); } @Override public void read(CompoundNBT compound) { super.read(compound); int [] arr = compound.getIntArray("ingredients"); System.out.print("reading ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n"); for(int i = 0; i < arr.length; i++){ ingredients[i] = FoodType.values()[arr[i]]; } } private int[] foodToIntArray(FoodType[] arr){ int[] result = new int[arr.length]; for(int i = 0; i < arr.length; i++){ result[i] = arr[i].ordinal(); } return result; } @Override public CompoundNBT write(CompoundNBT compound) { super.write(compound); int [] arr = foodToIntArray(ingredients); compound.putIntArray("ingredients", arr); System.out.print("writing ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n"); return compound; } public boolean addFood(FoodType food){ for(int i = 0; i < ingredients.length; i++){ if(ingredients[i] == FoodType.nothing){ markDirty(); ingredients[i] = food; return true; } } return false; } public void clearFoods(){ markDirty(); Arrays.fill(ingredients, FoodType.nothing); } public FoodType getIngredient(int index) { return ingredients[index]; } } I'm having 2 issues: 1. I can only get write() to be called by pausing the game, despite me calling markDirty() whenever data is updated. 2. Even if write() was called beforehand, the array gotten in read() is of length 0, which I assume means it couldn't find an NBT matching the key. I know that the array write() is attempting to write has the correct information because the System.out.print call prints the correct information, and the key is correct.
  10. My code was just this assert lightReader != null; assert pos != null; if(lightReader instanceof World){ // misc code never reached }else{ return MaterialColor.WATER.colorValue; } Like I said, not casting the ILightReader worked just fine. I was just curious if it could be cast to a World, and it doesn't seem like it can.
  11. I did that, and it just ended up never getting to the code I wanted it to.
  12. Not casting it worked, but I tried casting it anyway just to see what would happen and it crashed. It gave the error: java.lang.ClassCastException: net.minecraft.client.renderer.chunk.ChunkRenderCache cannot be cast to net.minecraft.world.World
  13. If you're playing a FTB pack, they have their own launcher at https://www.feed-the-beast.com/
  14. My BlockState became too complicated for the values I wanted to feed into my IBlockColor#getColor() implementation. Is there any alternative to getting values from the BlockState, or will I have to use a TER/TESR?
  15. As a note to those trying to use IBlockColor in 1.15, ColorHandlerEvent is now on the Mod Event Bus (Mod.EventBusSubscriber.Bus.MOD).
  16. Ah ok, thanks for clearing up the confusion. IBlockColor and IItemColor are definitely versatile enough for what I want to do.
  17. For example, if I had a block that I wanted to vary in hue based on its properties, and that hue could be any combination of the 3 color channels. Blockstates obviously wouldn't be feasible because that would be 255*255*255 conditions you'd need to define models for. I've heard of IBlockColor, but you have to register each color, correct? If so, that wouldn't be feasible either. Is there any other way to do this, with some weird rendering voodoo perhaps? Also, is there a way to do this with items too? EDIT: Did some more searching around and found out about TESR's, and it looks like they can do what I want for blocks. As far as items are concerned, I looked at the code for leather armor and found out that they store the color in NBT's.
  18. That's the very thing that confused me in the first place. When I saw that Block#getShape() was deprecated and BlockState#getShape() wasn't, I assumed exactly what you said in the last sentence, that VoxelShape information should be received from the BlockState rather than the Block. It's easy to just override Block#getShape() and have a switch-case or something that checks the BlockState and then returns the corresponding VoxelShape. It seems most people are doing it this way and Mojang does too, because it's own BlockState#getShape() method just calls Block#getShape(), and does pass in the contextual information. And that's what returns the VoxelShape. But if the concept is that you should be getting the VoxelShape of the BlockState rather than the Block, shouldn't you be keeping all VoxelShape information in the BlockState rather than the Block? You can do this simply by doing everything you do in Block#getShape() in BlockState#getShape(), but Mojang doesn't do this, and that's what doesn't make sense to me.
  19. Oh so it's just for the sake of convenience then. Still, it's so weird how Mojang decided to do this.
  20. Ah ok, I think I understand now. I should've looked more closely at the getShape() function of the BlockState class because it actually just calls the getShape() of the Block ?. I mean, this whole structure doesn't really make sense because you have a non-deprecated function that all it does is call a deprecated function, and said function is necessary if you want your block to have a shape... I'm lost as to what sort of advice Mojang is trying to give here by making this deprecated.
  21. In 1.15.1, the methods that work with VoxelShapes (i.e. getShape(), getCollisionShape()) are deprecated in the Block class, but aren't deprecated in the BlockState class. This change seems relatively new and I can't find any information about this on mcforge.readthedocs.io or anywhere else. There's also no documentation in the code itself saying why the methods are deprecated. I assume this means that you're supposed to override those methods in the BlockState class instead, but does this mean that for every Block, if I want to add VoxelShapes I need to make a new class that extends BlockState and then insert an instance of that class into the StateContainer of the Block? That doesn't sound right, and I'm really confused.
  22. Ah sorry, at first I misread what you said. Calling notSolid() on the Properties of the Block fixed the transparent face under the block, but the collision boxes and shadow rendering are still the same. I didn't use a VoxelShape at all, just a blockmodel json. The only methods that use it (getShape(), getCollisionShape(), etc.) are all deprecated in my version, probably because all the same things are handled by the block model json and the block state. Are there any special things that VoxelShapes can do that block states and block models can't?
  23. I tried changing the isSolid and blocksMovement properties of the Material to false, but that didn't work. Is that what you're talking about?
  24. My custom blocks are rendering like they are completely solid, how do I change this? (image link below because uploading it as an attachment and "Insert Image from URL" failed) https://ibb.co/nLpgwxz EDIT: I also noticed that the bounding boxes fill the entire block. How do I define these? Is a VoxelShape required for this?
×
×
  • Create New...

Important Information

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