Posted November 25, 20168 yr Hey there! So I'm making an "ability" where a player left clicks in the air with an empty hand, and a floating rock spawns and follows the player around. It's suppose to emulate earth bending from Avatar the Last Airbender. I have the PlayerInteractEvent.LeftClickEmpty set up correctly and the entity is spawning correctly, so that's all good. However, this is only being ran client side, meaning that when the EntityRock extends EntityTameable spawns, the super constructor for EntityLiving isn't running the "initEntityAI" code. I suppose I could just call it myself, but I'm willing to bet it's been written that way for a particular reason, perhaps meaning "logic" should be done server-side? Any thoughts or help are appreciated! Here's the event: @SubscribeEvent public void onLeftClick(PlayerInteractEvent.LeftClickEmpty event){ System.out.println("SIDE: " + event.getSide().toString()); EntityPlayer player = event.getEntityPlayer(); if(player.getHeldItem(EnumHand.MAIN_HAND) == null && player.equals(ClientProxy.MINECRAFT.thePlayer)){ EntityRock entity; entity = new EntityRock(player.worldObj); entity.setLocationAndAngles(player.posX, player.posY, player.posZ, MathHelper.wrapDegrees(player.worldObj.rand.nextFloat() * 360.0F), 0.0F); entity.rotationYawHead = entity.rotationYaw; entity.renderYawOffset = entity.rotationYaw; entity.onInitialSpawn(player.worldObj.getDifficultyForLocation(new BlockPos(entity)), (IEntityLivingData)null); player.worldObj.spawnEntityInWorld(entity); entity.playLivingSound(); ClientProxy.clientInfo.rocks.add(entity); } } Here's the EntityRock class: public class EntityRock extends EntityTameable { //Some code copied from Blaze class private EntityLivingBase owner; private double maxTravelDistance; private BlockPos startPosition; private double randomGeneratedOffset; private float heightOffset; /** ticks until heightOffset is randomized */ private int heightOffsetUpdateTime; private EntityAIFollowOwner followTask; private EntityAITargetBlock launhTask; private EntityAITargetEntity entityLaunchTask; public EntityRock(World worldIn) { super(worldIn); this.owner = ClientProxy.MINECRAFT.thePlayer; this.setSize(1f, 1f); this.experienceValue = 200; this.stepHeight = 1; randomGeneratedOffset = this.rand.nextInt(3); //0 - 2 //this.navigator = getNewNavigator(this.worldObj); this.setOwnerId(owner.getUniqueID()); this.posX = owner.posX + this.rand.nextInt(3); this.posY = owner.getEyeHeight() + 1; this.posZ = owner.posZ + this.rand.nextInt(3); this.setHomePosAndDistance(new BlockPos(posX, posY, posZ), Integer.MAX_VALUE); } @Override protected void initEntityAI(){ System.out.println("AI INIT"); //this.tasks.addTask(0, new EntityAIFollowBender(this, ClientProxy.MINECRAFT.thePlayer, 1f, 1.5f, 2.0f)); this.tasks.addTask(0, followTask = new EntityAIFollowOwner(this, 0.5D, 1.5f, 2f)); } @Override protected void applyEntityAttributes(){ super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(200.0D); //100 full hearts this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(1.0D); } public void launch(EntityPlayer player) { int yaw = (int)player.rotationYaw; if(yaw<0) { //due to the yaw running a -360 to positive 360 yaw += 360; } //not sure why it's that way yaw+=22; //centers coordinates you may want to drop this line yaw%=360; //and this one if you want a strict interpretation of the zones int facing = yaw/45; // 360degrees divided by 45 == 8 zones (4 normal direction, 4 diagonal) //----------------------- RayTraceResult result = player.worldObj.rayTraceBlocks(player.getPositionEyes(1.0f), player.getLookVec()); //remove task of following owner //add task of going to target //turn step height to 0 //mark start position //play sound if(result == null) return; if(result.typeOfHit != RayTraceResult.Type.MISS) this.tasks.removeTask(followTask); if(result.typeOfHit == RayTraceResult.Type.BLOCK) { BlockPos pos = new BlockPos(result.hitVec); this.tasks.addTask(0, launhTask = new EntityAITargetBlock(this, 2.0D, Integer.MAX_VALUE, pos)); } else if(result.typeOfHit == RayTraceResult.Type.ENTITY && result.entityHit instanceof EntityLivingBase) this.tasks.addTask(0, entityLaunchTask = new EntityAITargetEntity(this, false, (EntityLivingBase) result.entityHit)); this.stepHeight = 0; this.startPosition = new BlockPos(this.getPositionVector()); //play sound } @Override public EntityAgeable createChild(EntityAgeable ageable) { return null; } @Override public boolean canBeCollidedWith(){ return false; } @Override public void onCollideWithPlayer(EntityPlayer player){ if(player == owner){ return; } } @Override public void collideWithEntity(Entity entity){ } //@Override //protected PathNavigate getNewNavigator(World world){ //return new PathNavigateFollowAbility(this, world); //} @Override public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack){ if(hand.equals(EnumHand.MAIN_HAND)){ } //remove task of following owner //add task of going to target //turn step height to 0 //mark start position //play sound return true; } /** * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons * use this to react to sunlight and start to burn. */ public void onLivingUpdate() { super.onLivingUpdate(); if (!this.onGround && this.motionY < 0.0D) { this.motionY *= 0.6D; } this.onGround = true; //to make the path navigate believe the entity is on the ground so it can execute } protected void updateAITasks() { //may not want them to fly high incase they get in the way of shooting abilities super.updateAITasks(); --this.heightOffsetUpdateTime; if (this.heightOffsetUpdateTime <= 0) { this.heightOffsetUpdateTime = 100; this.heightOffset = 0.5F + (float)this.rand.nextGaussian() * 3.0F; } if (randomGeneratedOffset > 0 && owner != null && !owner.isDead && (Math.abs(this.posY - (owner.posY + owner.getEyeHeight())) > 1.0D)) { this.motionY += (0.30000001192092896D - this.motionY) * 0.30000001192092896D; this.motionY *= randomGeneratedOffset; this.isAirBorne = true; } this.onGround = true; //to make the path navigate believe the entity is on the ground so it can execute } public void fall(float distance, float damageMultiplier) { } @Override public boolean isAIDisabled(){return false;} protected SoundEvent getAmbientSound(){ return TestSounds.Guard; } protected SoundEvent getHurtSound(){return TestSounds.Guard;} protected SoundEvent getDeathSound(){return TestSounds.Guard;} }
November 25, 20168 yr You need to create a custom packet and send it to the server where it handles the spawning of the rock. VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect. Forge and vanilla BlockState generator.
November 25, 20168 yr Author You need to create a custom packet and send it to the server where it handles the spawning of the rock. Thank ya. I'll go find a tutorial on how to do that!
November 25, 20168 yr Author For anyone that happens to come across this same problem, just make sure that you registered your event class common/server side and not specifically just client side. Mine was fixed (well, believed to be fixed - I'll update the code tomorrow) by making sure it was registered common/server side.
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.