Posted December 29, 20204 yr Hello. I've been trying for some time now, to add a particle effect to my custom Dynamite TileEntity, identical to that of a TNTEntity, but can't seem to make the particle-effect appear. I reckon this have to do with the TileEntity's isActive-boolean being called on server, rather than client, resulting in the conditions never being checked on client-side. I'm unsure what the proper way of implementing this would be though, and I can't find a similar example of conditional ticking elsewhere in vanilla. I had a look at the Block method animateTick, but that one only seems to be called periodically, thus not producing the wanted results. DynamiteTileEntity: @Override public void tick() { if(isActive) { if(this.fuse <= 0) { this.remove(); if (!this.world.isRemote) { execute(); } } else { this.fuse--; if (this.world.isRemote) { this.world.addParticle(ParticleTypes.SMOKE, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 0.0D, 0.0D, 0.0D); } } } } DynamiteBlock: public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (world.isRemote) { return ActionResultType.CONSUME; } else { TileEntity tileentity = world.getTileEntity(pos); if (tileentity instanceof DynamiteTileEntity) { DynamiteTileEntity dynamiteTileEntity = (DynamiteTileEntity)tileentity; if(dynamiteTileEntity.isActive) { this.isActive = false; dynamiteTileEntity.deactivate(); CodingPanda.LOGGER.info("DISENGAGED"); return ActionResultType.SUCCESS; } else { dynamiteTileEntity.activate(); this.isActive = true; CodingPanda.LOGGER.info("ACTIVATED"); world.playSound((PlayerEntity)null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F); return ActionResultType.SUCCESS; } } return ActionResultType.CONSUME; } } Edited December 31, 20204 yr by StealthyNoodle
December 29, 20204 yr Block.onBlockActivate: if world.isRemote: do nothing else: revert DynamiteTileEntity.active DynamiteTileEntity.tick: if world.isRemote & active: spawn particles DynamiteTileEntity.active on client side is always false as it's never updated. Although it can be caused by something else but I can't access your full code so this is just my guess. You need to find a way to sync the value, using some default syncing methods in TileEntity/IForgeTileEntity e.g. getUpdatePacket and onDataPacket. There are also quite a lot of posts about this, you should have a look at them. Edited December 29, 20204 yr by poopoodice
December 30, 20204 yr Author On 12/29/2020 at 10:58 PM, poopoodice said: You need to find a way to sync the value, using some default syncing methods in TileEntity/IForgeTileEntity e.g. getUpdatePacket and onDataPacket. There are also quite a lot of posts about this, you should have a look at them. Thanks for your quick response! This should probably point me in the right direction - not sure if I grasp exactly how they're used yet, but will see if I can't figure it out. Here's the full code of both classes, should that be more insightful: DynamiteTileEntity: package com.snoodle.codingpanda.tileentities; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.world.Explosion; public class DynamiteTileEntity extends TileEntity implements ITickableTileEntity{ private final int FUSE = 160; private int fuse; public boolean isActive; public DynamiteTileEntity(final TileEntityType<?> tileEntityTypeIn) { super(tileEntityTypeIn); } public DynamiteTileEntity() { this(ModTileEntityTypes.DYNAMITE.get()); } @Override public void tick() { if(isActive) { if(this.fuse <= 0) { this.remove(); if (!this.world.isRemote) { execute(); } } else { this.fuse--; if (this.world.isRemote) { this.world.addParticle(ParticleTypes.SMOKE, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 0.0D, 0.0D, 0.0D); } } } } private void execute() { CodingPanda.LOGGER.info("TICK!"); this.world.createExplosion(null, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 6.0F, Explosion.Mode.BREAK); } public void activate() { isActive = true; fuse = FUSE; } public void deactivate() { isActive = false; } @Override public void read(BlockState state, CompoundNBT nbt) { super.read(state, nbt); this.fuse = nbt.getInt("fuse"); this.isActive = nbt.getBoolean("isActive"); } @Override public CompoundNBT write(CompoundNBT compound) { compound.putInt("fuse", this.fuse); compound.putBoolean("isActive", this.isActive); return super.write(compound); } } DynamiteBlock: package com.snoodle.codingpanda.blocks; import java.util.Random; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import com.snoodle.codingpanda.tileentities.DynamiteTileEntity; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; public class DynamiteBlock extends Block{ private boolean isActive; public DynamiteBlock(Properties properties) { super(properties); } public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (world.isRemote) { return ActionResultType.CONSUME; } else { TileEntity tileentity = world.getTileEntity(pos); if (tileentity instanceof DynamiteTileEntity) { DynamiteTileEntity dynamiteTileEntity = (DynamiteTileEntity)tileentity; if(dynamiteTileEntity.isActive) { this.isActive = false; dynamiteTileEntity.deactivate(); CodingPanda.LOGGER.info("DISENGAGED"); return ActionResultType.SUCCESS; } else { dynamiteTileEntity.activate(); this.isActive = true; CodingPanda.LOGGER.info("ACTIVATED"); world.playSound((PlayerEntity)null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F); return ActionResultType.SUCCESS; } } return ActionResultType.CONSUME; } } @Override public boolean hasTileEntity(BlockState state) { return true; } @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return ModTileEntityTypes.DYNAMITE.get().create(); } } Edited December 31, 20204 yr by StealthyNoodle Put code into spoilers
December 30, 20204 yr If I understand it correctly getUpdateTag provides the information that needs to be synced (check its doc), and getUpdatePacket provides the packet that going to be send to the client, I think it's fine to put any number for the tileEntityTypeIn (the second parameter of SUpdateTileEntityPacket), since it's hardcoded to check if the tileentity and the number matches. And then onDataPacket is called when the client has received the packet, it provides the data send from the server which you gather the information you need for client from it.
December 31, 20204 yr Author Thanks. I did some reading up on the docs in regards to syncing, but I'm worrying that my formatting here is still off (even though it seems to pick up the changes I do). The logger triggers whenever I call notifyBlockUpdate on the DynamiteBlock class, yet the isActive-bool still doesn't appear to change on client side. I've been looking at several cases, but few examples handling custom data through getUpdatePacket and onDataPacket. Here's what I've tried out so far (even though it still isn't functioning correctly) DynamiteBlock: package com.snoodle.codingpanda.blocks; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import com.snoodle.codingpanda.tileentities.DynamiteTileEntity; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; public class DynamiteBlock extends Block{ public DynamiteBlock(AbstractBlock.Properties properties) { super(properties); } public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (world.isRemote) { return ActionResultType.SUCCESS; } else { TileEntity tileentity = world.getTileEntity(pos); if (tileentity instanceof DynamiteTileEntity) { DynamiteTileEntity dynamiteTileEntity = (DynamiteTileEntity)tileentity; if(dynamiteTileEntity.isActive) { dynamiteTileEntity.deactivate(); CodingPanda.LOGGER.info("DEACTIVATED"); } else { dynamiteTileEntity.activate(); CodingPanda.LOGGER.info("ACTIVATED"); world.playSound((PlayerEntity)null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F); } world.notifyBlockUpdate(pos, state, state, 2); return ActionResultType.CONSUME; } return ActionResultType.CONSUME; } } @Override public boolean hasTileEntity(BlockState state) { return true; } @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return ModTileEntityTypes.DYNAMITE.get().create(); } } DynamiteTileEntity: package com.snoodle.codingpanda.tileentities; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.world.Explosion; public class DynamiteTileEntity extends TileEntity implements ITickableTileEntity{ private final int FUSE = 160; private int fuse; public boolean isActive; public DynamiteTileEntity(final TileEntityType<?> tileEntityTypeIn) { super(tileEntityTypeIn); } public DynamiteTileEntity() { this(ModTileEntityTypes.DYNAMITE.get()); } @Override public void tick() { if(isActive) { if(this.fuse <= 0) { this.remove(); if (!this.world.isRemote) { execute(); } } else { this.fuse--; if (this.world.isRemote) { this.world.addParticle(ParticleTypes.SMOKE, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 0.0D, 0.0D, 0.0D); CodingPanda.LOGGER.info("I'm getting called"); } } } } private void execute() { CodingPanda.LOGGER.info("TICK!"); this.world.createExplosion(null, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 6.0F, Explosion.Mode.BREAK); } public void activate() { isActive = true; fuse = FUSE; } public void deactivate() { isActive = false; } @Override public SUpdateTileEntityPacket getUpdatePacket(){ CompoundNBT compound = new CompoundNBT(); compound.putBoolean("isActive", this.isActive); CodingPanda.LOGGER.info("wrote isActive to " + this.isActive); return new SUpdateTileEntityPacket(getPos(), -1, compound); } @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt){ CompoundNBT tag = pkt.getNbtCompound(); if(this.world.isRemote) { this.isActive = tag.getBoolean("isActive"); CodingPanda.LOGGER.info("loaded isActive is " + this.isActive); } } @Override public void read(BlockState state, CompoundNBT nbt) { super.read(state, nbt); this.fuse = nbt.getInt("fuse"); this.isActive = nbt.getBoolean("isActive"); } @Override public CompoundNBT write(CompoundNBT compound) { compound.putInt("fuse", this.fuse); compound.putBoolean("isActive", this.isActive); return super.write(compound); } } Edited December 31, 20204 yr by StealthyNoodle
December 31, 20204 yr Author Wooh, got it! I continued reading about getUpdatePacket and onDataPacket, and stumbled over @diesieben07's post on the matter: I was certain I had to handle all the data through getUpdateTag and onDataPacket, but seems like the data first has to be sent through getUpdateTag (which is then processed by handleUpdateTag). I still still struggle with wrapping my head around exactly how it works, but I think I'm starting to grasp the concept. Here's the latest, working version. Some of the code has been optimized and moved around since last time. DynamiteBlock: package com.snoodle.codingpanda.blocks; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import com.snoodle.codingpanda.tileentities.DynamiteTileEntity; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; public class DynamiteBlock extends Block{ public DynamiteBlock(AbstractBlock.Properties properties) { super(properties); } public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (world.isRemote) { world.notifyBlockUpdate(pos, state, state, 2); return ActionResultType.SUCCESS; } else { TileEntity tileentity = world.getTileEntity(pos); if (tileentity instanceof DynamiteTileEntity) { DynamiteTileEntity dynamiteTileEntity = (DynamiteTileEntity)tileentity; dynamiteTileEntity.toggle(); CodingPanda.LOGGER.info("ACTIVATED"); world.notifyBlockUpdate(pos, state, state, 2); return ActionResultType.CONSUME; } return ActionResultType.CONSUME; } } @Override public boolean hasTileEntity(BlockState state) { return true; } @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return ModTileEntityTypes.DYNAMITE.get().create(); } } DynamiteTileEntity: package com.snoodle.codingpanda.tileentities; import com.snoodle.codingpanda.CodingPanda; import com.snoodle.codingpanda.setup.ModTileEntityTypes; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import net.minecraft.world.Explosion; public class DynamiteTileEntity extends TileEntity implements ITickableTileEntity{ private final int FUSE = 160; private int fuse; private boolean isActive; public DynamiteTileEntity() { super(ModTileEntityTypes.DYNAMITE.get()); } @Override public void tick() { if(isActive) { if(this.fuse <= 0) { this.remove(); if (!this.world.isRemote) { execute(); } } else { this.fuse--; if (this.world.isRemote) { this.world.addParticle(ParticleTypes.SMOKE, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 0.0D, 0.0D, 0.0D); CodingPanda.LOGGER.info("I'm getting called"); } } } if (this.world.isRemote) { CodingPanda.LOGGER.info("isActive is " + isActive); } } private void execute() { CodingPanda.LOGGER.info("TICK!"); this.world.createExplosion(null, this.getPos().getX() + 0.5D, this.getPos().getY() + 0.5D, this.getPos().getZ() + 0.5D, 6.0F, Explosion.Mode.BREAK); } public void toggle() { if(!isActive) { world.playSound((PlayerEntity)null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F); isActive = true; fuse = FUSE; } else { isActive = false; } this.markDirty(); } @Override public CompoundNBT getUpdateTag() { CompoundNBT nbtTag = new CompoundNBT(); nbtTag.putBoolean("isActive", this.isActive); write(nbtTag); return nbtTag; } @Override public void handleUpdateTag(BlockState blockState, CompoundNBT parentNBTTagCompound) { this.read(blockState, parentNBTTagCompound); } @Override public SUpdateTileEntityPacket getUpdatePacket(){ CodingPanda.LOGGER.info("wrote isActive to " + this.isActive); return new SUpdateTileEntityPacket(getPos(), -1, getUpdateTag()); } @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt){ CompoundNBT tag = pkt.getNbtCompound(); this.isActive = tag.getBoolean("isActive"); this.read(this.getBlockState(), pkt.getNbtCompound()); CodingPanda.LOGGER.info("loaded isActive is " + this.isActive); } @Override public void read(BlockState state, CompoundNBT nbt) { super.read(state, nbt); this.fuse = nbt.getInt("fuse"); this.isActive = nbt.getBoolean("isActive"); } @Override public CompoundNBT write(CompoundNBT compound) { compound.putInt("fuse", this.fuse); compound.putBoolean("isActive", this.isActive); return super.write(compound); } } Thanks a lot for helping out, poopoodice! Edited December 31, 20204 yr by StealthyNoodle
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.