Jump to content

Entity Multipart problem [1.15.2]


Narlecks

Recommended Posts

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;
   }
}

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

 

 

Link to comment
Share on other sites

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]);
		}
		
	}

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

×
×
  • Create New...

Important Information

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