Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

Version: 1.15.2

I'm trying to make a mob that has multiple hitboxes, i take a look on Ender Dragon's code but when i hit the entity, it just dont works.

(in debug mode(f3) it shows me the hitboxes correctly)

 

NewEntity.class

public class NewEntity extends MultiPartEntity {
	protected final MultiPartEntityPart[] bodyParts;
	public final MultiPartEntityPart headPart;
	public final MultiPartEntityPart bodyPart;
	public NewEntity(EntityType<? extends MultiPartEntity> type, World worldIn) {
		super(type, worldIn);
		this.bodyPart = new MultiPartEntityPart(this, "body", 2.0F, 1.0F);
		this.headPart = new MultiPartEntityPart(this, "head", 1.0F, 1.0F);
		this.bodyParts = new MultiPartEntityPart[]{this.headPart,this.bodyPart};
	}
	@Override
	protected void registerAttributes() {
		super.registerAttributes();
		this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(100);
	}

	public boolean attackEntityFrom(DamageSource source, float amount) {
		return false;
	}
	public boolean attackEntityFrom(MultiPartEntityPart entityPart, DamageSource source, float damage) {
		System.out.println(entityPart.partName);
		return true;
	}
	
	public boolean canBeCollidedWith() {
		return false;
	}
	@Override
	public boolean canBePushed() {
		return false;
	}


	@Override
	public void livingTick() {
		super.livingTick();
		Vec3d[] avec3d = new Vec3d[this.bodyParts.length];

		for(int j = 0; j < this.bodyParts.length; ++j) {
			avec3d[j] = new Vec3d(this.bodyParts[j].getPosX(), this.bodyParts[j].getPosY(), this.bodyParts[j].getPosZ());
		}
		bodyParts[0].setPosition(0,0 + 1f,0);
		bodyParts[1].setPosition(0,0 - 0.2f,0);
		for(int l = 0; l < this.bodyParts.length; ++l) {
			this.bodyParts[l].prevPosX = avec3d[l].x;
			this.bodyParts[l].prevPosY = avec3d[l].y;
			this.bodyParts[l].prevPosZ = avec3d[l].z;
			this.bodyParts[l].lastTickPosX = avec3d[l].x;
			this.bodyParts[l].lastTickPosY = avec3d[l].y;
			this.bodyParts[l].lastTickPosZ = avec3d[l].z;
		}

	}
	@Override
	public MultiPartEntityPart[] getAllParts() {
		return this.bodyParts;
	}
}

MultiPartEntity.class

public abstract class MultiPartEntity extends CreatureEntity {
	
	protected MultiPartEntity(EntityType<? extends CreatureEntity> type, World worldIn) {
		super(type, worldIn);
	}
	
	public abstract boolean attackEntityFrom(MultiPartEntityPart entityPart, DamageSource source, float damage);
	
	public abstract MultiPartEntityPart[] getAllParts();
	
}

MultiPartEntityPart.class:

public class MultiPartEntityPart extends Entity {
   public final MultiPartEntity parentEntity;
   public final String partName;
   private final EntitySize boxSize;

   public MultiPartEntityPart(MultiPartEntity parentEntity, String partName, float widthIn, float HeightIn) {
 		super(parentEntity.getType(), parentEntity.world);
 	      this.boxSize = EntitySize.flexible(widthIn, HeightIn);
 	      this.recalculateSize();
 	      this.parentEntity = (MultiPartEntity) parentEntity;
 	      this.partName = partName;
 	}
  
   protected void registerData() {
   }
   
   protected void readAdditional(CompoundNBT compound) {
   }

   protected void writeAdditional(CompoundNBT compound) {
   }

   public boolean canBeCollidedWith() {
      return true;
   }
   public boolean attackEntityFrom(DamageSource source, float amount) {
      return this.parentEntity.attackEntityFrom(this, source, amount);
   }

   public boolean isEntityEqual(Entity entityIn) {
      return this == entityIn || this.parentEntity == entityIn;
   }

   public IPacket<?> createSpawnPacket() {
      throw new UnsupportedOperationException();
   }

   public EntitySize getSize(Pose poseIn) {
      return this.boxSize;
   }
}

 

22 minutes ago, Narlecks said:

public boolean attackEntityFrom(DamageSource source, float amount) { return false; } public boolean attackEntityFrom(MultiPartEntityPart entityPart, DamageSource source, float damage) { System.out.println(entityPart.partName); return true; }

Yes, the console output is occurring only whenever you hit the parts. However, it will not cause any damage to the actual entity as that returns false. You need a better descriptor rather than 'it just doesn't work'.

  • Author
4 minutes ago, ChampionAsh5357 said:

Yes, the console output is occurring only whenever you hit the parts. However, it will not cause any damage to the actual entity as that returns false. You need a better descriptor rather than 'it just doesn't work'.

You are right, my bad.

When I hit the entity, in the console I don't get any messages

  • Author

It never reaches AttackEntityFrom because the other hitboxes even though they exist, I can't hit them.

3 minutes ago, Narlecks said:

It never reaches AttackEntityFrom because the other hitboxes even though they exist, I can't hit them.

You just ignored what I said. You're telling me an issue based on runtime testing and not on debugging. You can go all the way into Minecraft#clickMouse and put a breakpoint over the case where the RayTraceResult is an ENTITY and view what's getting called where and why. However, telling me the same problem without debugging the process like I mentioned above is just repetition and not solving the issue.

 

So, follow the code from where the entity is clicked on all the way to it's final result. If you are in fact targeting an entity, it should be recognized by the resulting ray trace. You should even be able to verify that your mouse is hovering over the existing entity by simply opening the debug menu.

  • Author
On 10/18/2020 at 3:54 PM, ChampionAsh5357 said:

You just ignored what I said. You're telling me an issue based on runtime testing and not on debugging. You can go all the way into Minecraft#clickMouse and put a breakpoint over the case where the RayTraceResult is an ENTITY and view what's getting called where and why. However, telling me the same problem without debugging the process like I mentioned above is just repetition and not solving the issue.

 

So, follow the code from where the entity is clicked on all the way to it's final result. If you are in fact targeting an entity, it should be recognized by the resulting ray trace. You should even be able to verify that your mouse is hovering over the existing entity by simply opening the debug menu.

Thanks for the suggestion!, i solved that problem but i found another..

The problem is, the entity parts have different IDs on client and server

So, for example.. when i hit the head, in client-side the hit is received by the head but in server-side is received by the body bc the ids collide

Do you have an idea why that can happen?

Tell me if u need specific information

  • Author

one thing I forgot to say is that following the EnderDragon's code i came across this:

public void handleSpawnMob(SSpawnMobPacket packetIn) {
		PacketThreadUtil.checkThreadAndEnqueue(packetIn, (ClientPlayNetHandler) (Object)this, this.client);
		double d0 = packetIn.getX();
		double d1 = packetIn.getY();
		double d2 = packetIn.getZ();
		float f = (float)(packetIn.getYaw() * 360) / 256.0F;
		float f1 = (float)(packetIn.getPitch() * 360) / 256.0F;
		LivingEntity livingentity = (LivingEntity)EntityType.create(packetIn.getEntityType(), this.client.world);
		if (livingentity != null) {
			livingentity.setPacketCoordinates(d0, d1, d2);
			livingentity.renderYawOffset = (float)(packetIn.getHeadPitch() * 360) / 256.0F;
			livingentity.rotationYawHead = (float)(packetIn.getHeadPitch() * 360) / 256.0F;
			if (livingentity instanceof EnderDragonEntity) {
				EnderDragonPartEntity[] aenderdragonpartentity = ((EnderDragonEntity)livingentity).getDragonParts();

				for(int i = 0; i < aenderdragonpartentity.length; ++i) {
					aenderdragonpartentity[i].setEntityId(i + packetIn.getEntityID());
				}
			}
			if (livingentity instanceof MultiPartEntity) {
				MultiPartEntityPart[] multipartentitypart = ((MultiPartEntity)livingentity).getAllParts();
				for(int i = 0; i < multipartentitypart.length; ++i) {
					multipartentitypart[i].setEntityId(i + packetIn.getEntityID());
				}
			}

			livingentity.setEntityId(packetIn.getEntityID());
			livingentity.setUniqueId(packetIn.getUniqueId());
			livingentity.setPositionAndRotation(d0, d1, d2, f, f1);
			livingentity.setMotion((double)((float)packetIn.getVelocityX() / 8000.0F), (double)((float)packetIn.getVelocityY() / 8000.0F), (double)((float)packetIn.getVelocityZ() / 8000.0F));
			this.world.addEntity(packetIn.getEntityID(), livingentity);
			if (livingentity instanceof BeeEntity) {
				boolean flag = ((BeeEntity)livingentity).isAngry();
				BeeSound beesound;
				if (flag) {
					beesound = new BeeAngrySound((BeeEntity)livingentity);
				} else {
					beesound = new BeeFlightSound((BeeEntity)livingentity);
				}

				this.client.getSoundHandler().play(beesound);
			}
		} else {
			LOGGER.warn("Skipping Entity with id {}", (int)packetIn.getEntityType());
		}

	}

I'm not sure if the error is in this part, but as you can see I added a condition to modify the entityID of each part, I tried it and it works as it should on clientSide

 

 

4 hours ago, Narlecks said:

I'm not sure if the error is in this part, but as you can see I added a condition to modify the entityID of each part, I tried it and it works as it should on clientSide

Yes, you got it.

  • Author
6 hours ago, ChampionAsh5357 said:

Yes, you got it.

The problem is, it only works in clientside, the id's on serverside are not the same

4 hours ago, Narlecks said:

The problem is, it only works in clientside, the id's on serverside are not the same

Then sync the serverside ids to the client for each part.

  • Author
9 hours ago, ChampionAsh5357 said:

Then sync the serverside ids to the client for each part.

Any idea where Minecraft does that? or i put it in the same place using packets?

You should specify the spawning packet as NetworkHooks#getSpawnPacket and use IEntityAdditionalSpawnData to send the ids of each multipart to the client so they may be synchronized.

  • Author
22 hours ago, ChampionAsh5357 said:

You should specify the spawning packet as NetworkHooks#getSpawnPacket and use IEntityAdditionalSpawnData to send the ids of each multipart to the client so they may be synchronized.

in the first instance it worked, but for some reason when hitting it keeps getting different id's on server / client.

Did I made a mistake while implementing IEntityAdditionalSpawnData?

 

	@Override
	public IPacket<?> createSpawnPacket() {
		return NetworkHooks.getEntitySpawningPacket(this);
	}
	@Override
	public void writeSpawnData(PacketBuffer buffer) {
		int[] id = new int[getAllParts().length];
		for(int i=0;i<getAllParts().length;i++) {
			getAllParts()[i].setEntityId(i+this.getEntityId());
			id[i] = i+this.getEntityId();
		}
		buffer.writeVarIntArray(id);
		
	}
	@Override
	public void readSpawnData(PacketBuffer additionalData) {
		int[] id = additionalData.readVarIntArray();
		for(int i=0;i<getAllParts().length;i++) {
			getAllParts()[i].setEntityId(id[i]);
		}
		
	}

 

You shouldn't need to set the data on the server. Those values are handled via AtomicInteger#incrementAndGet. Therefore, you know that the parts will have the next ids after your entity (e.g. if your main id is 23, then your parts will always be 24 and 25). All you really need to do is just set the entity id itself when you are reading the data with it's specified offset. Nothing needs to be sent to the client.

This might be the error you are facing as you could be changing the id when the server already has a set value, but I'm not sure. However, you should try the above and see if it solves your issue.

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.