Jump to content

[1.16.1] Flying Entity Speed


DavidQF555

Recommended Posts

public class CustomEntity extends FlyingEntity {

	public CustomEntity(EntityType<? extends FlyingEntity> type, World worldIn) {
		super(type, worldIn);
		moveController = new FlyingMovementController(this, 60, true);
	}

	public static AttributeModifierMap.MutableAttribute setAttributes(){
		return MobEntity.func_233666_p_()
				.func_233815_a_(Attributes.field_233822_e_, (double) 5.0f)
				.func_233815_a_(Attributes.field_233821_d_, (double) 5.0f)
				.func_233815_a_(Attributes.field_233818_a_, 10);
	}

	@Override
	public void registerGoals() {
		super.registerGoals();
		goalSelector.addGoal(0, new FollowOwnerGoal());
		goalSelector.addGoal(1, new LookAtGoal(this, PlayerEntity.class, 5));
	}

	@Override
	protected PathNavigator createNavigator(World worldIn) {
		return new FlyingPathNavigator(this, worldIn);
	}

	private class FollowOwnerGoal extends Goal {

		private static final int DISTANCE = 5;

		private FollowOwnerGoal() {
			setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
		}

		@Override
		public boolean shouldExecute() {
			return getOwner() != null && getDistanceSq(getOwner()) > DISTANCE * DISTANCE;
		}

		@Override
		public boolean shouldContinueExecuting() {
			return shouldExecute() && !getNavigator().noPath();
		}

		@Override
		public void tick() {
			getNavigator().tryMoveToXYZ(getOwner().getPosX(), getOwner().getPosYEye(), getOwner().getPosZ(), 1);
		}
	}
}
private void setup(final FMLCommonSetupEvent event) {
		DeferredWorkQueue.runLater(() -> {
			GlobalEntityTypeAttributes.put(RegistryHandler.CUSTOM_ENTITY.get(), CustomEntity.setAttributes().func_233813_a_());
		});
	}

This should be all the relevant code. Basically, no matter what the speed attribute of my entity is, it is always insanely slow. I thought it might have to do with the FlyingPathNavigator and MovementController's just not using the right speed, but I also changed the generic movement speed attribute and nothing changed. I feel like I probably needed to override another method or something. What have I done wrong?

Link to comment
Share on other sites

6 hours ago, DavidQF555 said:

getNavigator().tryMoveToXYZ(getOwner().getPosX(), getOwner().getPosYEye(), getOwner().getPosZ(), 1);

A number 1 you pass here is actually double and defines movement speed multiplier.

Resulting movement speed will equal to speed attribute * this parameter, as shown at MovementController::tick.

So, you may try change 1 to 1.0d, and then set there, for example, 2.0d.

Edited by Dzuchun

Everything said above may be absolutely wrong. No rights reserved.

Link to comment
Share on other sites

5 hours ago, Dzuchun said:

A number 1 you pass here is actually double and defines movement speed multiplier.

Resulting movement speed will equal to speed attribute * this parameter, as shown at MovementController::tick.

So, you may try change 1 to 1.0d, and then set there, for example, 2.0d.

I changed it to 2.0D and nothing has really changed. Using livingTick() to print out speed, it constantly switches between the number I set in the tryMoveToXYZ() and 0. It just ignores my attribute, and the speed printed is also not really applied to how fast the actual entity is. I put in 100.0D and nothing changed. 

Link to comment
Share on other sites

Where from do you execute setAttributes method?

It's static, so it does not override something.

Also, you'd better provide full source code(using github, for example), because usually errors are in the places you do not expect them :)

Everything said above may be absolutely wrong. No rights reserved.

Link to comment
Share on other sites

19 minutes ago, Dzuchun said:

Where from do you execute setAttributes method?

It's static, so it does not override something.

Also, you'd better provide full source code(using github, for example), because usually errors are in the places you do not expect them :)

The setAttributes method is in the code I sent, in the Main class. I know it works because FlyingPathNavigator does not even work without a flying speed. Also, its health is actually 10. 

Link to comment
Share on other sites

Let me just post the code of all the classes that have some relevance: 

ublic class CustomEntity extends FlyingEntity {

  private LivingEntity owner;
  
	public CustomEntity(EntityType<? extends FlyingEntity> type, World worldIn, LivingEntity owner) {
		super(type, worldIn);
		moveController = new FlyingMovementController(this, 60, true);
      this.owner = owner;
	}
  
  public LivingEntity getOwner(){
   return owner; 
  }

	public static AttributeModifierMap.MutableAttribute setAttributes(){
		return MobEntity.func_233666_p_()
				.func_233815_a_(Attributes.field_233822_e_, (double) 5.0f)
				.func_233815_a_(Attributes.field_233821_d_, (double) 5.0f)
				.func_233815_a_(Attributes.field_233818_a_, 10);
	}

	@Override
	public void registerGoals() {
		super.registerGoals();
		goalSelector.addGoal(0, new FollowOwnerGoal());
		goalSelector.addGoal(1, new LookAtGoal(this, PlayerEntity.class, 5));
	}

	@Override
	protected PathNavigator createNavigator(World worldIn) {
		return new FlyingPathNavigator(this, worldIn);
	}

	private class FollowOwnerGoal extends Goal {

		private static final int DISTANCE = 5;

		private FollowOwnerGoal() {
			setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
		}

		@Override
		public boolean shouldExecute() {
			return getOwner() != null && getDistanceSq(getOwner()) > DISTANCE * DISTANCE;
		}

		@Override
		public boolean shouldContinueExecuting() {
			return shouldExecute() && !getNavigator().noPath();
		}

		@Override
		public void tick() {
			getNavigator().tryMoveToXYZ(getOwner().getPosX(), getOwner().getPosYEye(), getOwner().getPosZ(), 1);
		}
	}
}
@SuppressWarnings("deprecation")
@Mod("testmod")
public class TestMod {

	public static final String MOD_ID = "testmod";
	public static final ItemGroup TAB = new ItemGroup("testmod") {
		@Override
		public ItemStack createIcon() {
			return new ItemStack(RegistryHandler.RUBY.get());
		}
	};

	public TestMod() {
		FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
		FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);

		RegistryHandler.init();

		MinecraftForge.EVENT_BUS.register(this);
	}

	private void setup(final FMLCommonSetupEvent event) {
		DeferredWorkQueue.runLater(() -> {
			GlobalEntityTypeAttributes.put(RegistryHandler.CUSTOM_ENTITY.get(), CustomEntity.setAttributes().func_233813_a_());
		});
	}

	private void doClientStuff(final FMLClientSetupEvent event) {}

}
public class RegistryHandler {

	public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITIES, TestMod.MOD_ID);

	public static final RegistryObject<EntityType<CustomEntity>> CUSTOM_ENTITY = ENTITY_TYPES.register("custom_entity", () -> EntityType.Builder.create(new CustomFactory(), EntityClassification.AMBIENT).size(0.9f, 0.9f).build(new ResourceLocation(TestMod.MOD_ID, "custom_entity").toString()));

	public static void init() {
		IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
		ENTITY_TYPES.register(bus);
	}
public class CustomFactory implements EntityType.IFactory<CustomEntity> {
		@Override
		public CustomEntity create(EntityType<CustomEntity> type, World world) {
			return new CustomEntity(type, world, null);
		}
	}
public class CustomItem extends BasicItem {

	@Override
	public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
		Vector3d spawn = playerIn.getEyePosition(1).add(playerIn.getLookVec().mul(2, 2, 2));
		CustomEntity light = new CustomEntity(RegistryHandler.CUSTOM_ENTITY.get(), worldIn, playerIn);
		if(light.canSpawn(worldIn, SpawnReason.MOB_SUMMONED)) {
			light.setPosition(spawn.x, spawn.y, spawn.z);
			worldIn.addEntity(light);
			ItemStack item = playerIn.getHeldItem(handIn);
			item.setCount(item.getCount() - 1);
			playerIn.setHeldItem(handIn, item);
		}
		return ActionResult.resultPass(playerIn.getHeldItem(handIn));
	}
}

 

Link to comment
Share on other sites

1 hour ago, DavidQF555 said:

public class CustomFactory implements EntityType.IFactory<CustomEntity> 
{ 
  @Override
  public CustomEntity create(EntityType<CustomEntity> type, World world)
  { 
    return new CustomEntity(type, world, null); 
  } 
}

 

You may use lambda-expression for that.

It won't help you at all, but you'll get rid of some excess code.

1 hour ago, DavidQF555 said:

private class FollowOwnerGoal extends Goal

Minecraft has FollowOwnerGoal for you to have a template (it requires TameableEntity).

The problem may be that you set a new path every tick. Stock FollowOwnerGoal does it every 10 ticks. (not sure)

Everything said above may be absolutely wrong. No rights reserved.

Link to comment
Share on other sites

1 hour ago, Dzuchun said:

You may use lambda-expression for that.

It won't help you at all, but you'll get rid of some excess code.

Minecraft has FollowOwnerGoal for you to have a template (it requires TameableEntity).

The problem may be that you set a new path every tick. Stock FollowOwnerGoal does it every 10 ticks. (not sure)

I checked it, it basically does the same thing except check more conditions like whether sitting or not. I updated my code to: 

private class FollowOwnerGoal extends Goal {

		private static final int DISTANCE = 5;
		private static final int COOLDOWN = 200;
		private int cooldown;

		private FollowOwnerGoal() {
			setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
			cooldown = 0;
		}

		@Override
		public boolean shouldExecute() {
			return getOwner() != null && getDistanceSq(getOwner()) > DISTANCE * DISTANCE;
		}

		@Override
		public boolean shouldContinueExecuting() {
			return shouldExecute() && !getNavigator().noPath();
		}
		
		@Override
		public void resetTask() {
			cooldown = 0;
			getNavigator().clearPath();
		}

		@Override
		public void tick() {
			cooldown = Math.max(0, cooldown - 1);
			if(cooldown == 0) {
				getNavigator().tryMoveToXYZ(getOwner().getPosX(), getOwner().getPosYEye(), getOwner().getPosZ(), 100.0D);
				cooldown = COOLDOWN;
			}
		}
	}

To attempt to replicate the Tameable one, but it still has the same effect. I think it has something to do with either switching to FlyingMovementController or FlyingPathNavigator, but I cannot figure out what the problem is. 

Link to comment
Share on other sites

I used to experiment with creating custom entities at 1.15.2, but seems like not much changed since then*nevermind*. Here is my repository.

Please, do not use it as manual, it's terrible in fact. All you need about AI is at HappyDolphinEntity class, which defines a pink horned flying dolphin that eats flowers accidentally (don't ask me why).

In that class you may see my own WanderingGoal, (because I was to stupid to use existing one, yea) and all sort of things I made to get it working.

I'm really sorry for posting this code here, and once again, THIS IS NOT A MANUAL.

Read sign.

Edited by Dzuchun

Everything said above may be absolutely wrong. No rights reserved.

Link to comment
Share on other sites

33 minutes ago, Dzuchun said:

I used to experiment with creating custom entities at 1.15.2, but seems like not much changed since then. Here is my repository.

Please, do not use it as manual, it's terrible in fact. All you need about AI is at HappyDolphinEntity class, which defines a pink horned flying dolphin that eats flowers accidentally (don't ask me why).

In that class you may see my own WanderingGoal, (because I was to stupid to use existing one, yea) and all sort of things I made to get it working.

I'm really sorry for posting this code here, and once again, THIS IS NOT A MANUAL.

Read sign.

private class FollowOwnerGoal extends Goal {

		private static final int DISTANCE = 5;

		private FollowOwnerGoal() {
			setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
		}

		@Override
		public boolean shouldExecute() {
			return getNavigator().noPath() && getOwner() != null && getDistanceSq(getOwner()) > DISTANCE * DISTANCE;
		}

		@Override
		public boolean shouldContinueExecuting() {
			return false;
		}
		
		@Override
		public void startExecuting() {
			super.startExecuting();
			getNavigator().tryMoveToXYZ(getOwner().getPosX(), getOwner().getPosYEye(), getOwner().getPosZ(), 100);
		}
	}

I really simplified mine. Your code has a lot more factors, but I just need it to move, so this should work, but it doesn't consider the speed at all

Link to comment
Share on other sites

1 minute ago, DavidQF555 said:

@Override
public boolean shouldContinueExecuting() 
{ 
 return false;
}

 

This means that after 1 tick your task gets interrupted and another one selected.

Everything said above may be absolutely wrong. No rights reserved.

Link to comment
Share on other sites

private class FollowOwnerGoal extends Goal {

		private static final double DISTANCE = 5;

		private FollowOwnerGoal() {
			setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
		}

		@Override
		public boolean shouldExecute() {
			Entity owner = getOwner();
			if (owner == null) {
				return false;
			} else if (owner.isSpectator()) {
				return false;
			} else return !(getDistanceSq(owner) < DISTANCE * DISTANCE);
		}

		/**
		 * Returns whether an in-progress EntityAIBase should continue executing
		 */
		public boolean shouldContinueExecuting() {
			if (getNavigator().noPath() || getOwner() == null) {
				return false;
			} else {
				return !(getDistanceSq(getOwner()) <= DISTANCE * DISTANCE);
			}
		}

		/**
		 * Reset the task's internal state. Called when this task is interrupted by another one
		 */
		public void resetTask() {
		getNavigator().clearPath();
			LOGGER.info("Reset");
		}

		/**
		 * Keep ticking a continuous task that has already been started
		 */
		public void tick() {
			if(getOwner() != null) {
				getLookController().setLookPositionWithEntity(getOwner(), 10.0F, getVerticalFaceSpeed());
				if (!getLeashed() && !isPassenger()) {
					LOGGER.info("controller: " + moveController.getSpeed() + " AI: " + getAIMoveSpeed());
					getNavigator().tryMoveToEntityLiving(getOwner(), 100);

				}
			}
		}
	}

I've basically copied the Tameable version now. Is it normal for the "reset" to be called every 5 ticks? The other logger message is completely normal

Link to comment
Share on other sites

  • 3 weeks later...

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



×
×
  • Create New...

Important Information

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