LeeCrafts Posted May 18, 2022 Posted May 18, 2022 (edited) Hello, I was playing around with changing the size of the AABB and discovered something that stumped me. As seen in my previous posts, I have been able to increase the size of the player with a custom status effect. I have been trying to do the same for all living entities, not just the player. Therefore, I--ideally--would not have to change the AABB by hardcoded values, like below: // overriding MobEffect::applyEffectTick in my custom effect class pLivingEntity.setBoundingBox(new AABB(pLivingEntity.getX()+2.5, pLivingEntity.getY()+3.6, pLivingEntity.getZ()+2.5, pLivingEntity.getX()-2.5, pLivingEntity.getY(), pLivingEntity.getZ()-2.5)); Simply using something like "pLivingEntity.setBoundingBox(pLivingEntity.getBoundingBox().inflate(2.5, 1.8, 2.5))" would be dangerous because the entity's AABB would expand to astronomical proportions. So I tried using a capability that stores the "original" dimensions of the entity's AABB when that entity joins the world (e.g. EntityJoinWorldEvent). This is what it looked like: // custom capability that stores the original AABB dimensions of the entity pLivingEntity.getCapability(ModCapabilities.HITBOX_CAPABILITY).ifPresent(iHitbox -> { Hitbox hitbox = (Hitbox) iHitbox; pLivingEntity.setBoundingBox(new AABB( pLivingEntity.getX() + hitbox.originalXSize * 4.2, pLivingEntity.getY() + hitbox.originalYSize * 2, pLivingEntity.getZ() + hitbox.originalZSize * 4.2, pLivingEntity.getX() - hitbox.originalXSize * 4.2, pLivingEntity.getY(), pLivingEntity.getZ() - hitbox.originalZSize * 4.2) ); }); When I tested this, the changed hitbox collides with entities but not with blocks. I am quite confused because changing the AABB by hardcoded values worked for both entity and block collision. How? Previous post for reference (where I set the bounding box): https://forums.minecraftforge.net/topic/111159-version-1182-solved-custom-status-effect-that-changes-the-players-size-part-ii/?do=findComment&comment=496252 Edited May 20, 2022 by LeeCrafts Quote
LeeCrafts Posted May 20, 2022 Author Posted May 20, 2022 (edited) Update: I realized I don't need capabilities. In fact, I don't need to override applyEffectTick at all. But it seems like I need reflections. The increased hitbox size now works for both entity and block collision--with a little drawback. This is what it looks like so far: // this event handler checks every tick if the living entity has the "big" effect @SubscribeEvent public static void entitySizeChange(LivingEvent.LivingUpdateEvent event) { LivingEntity livingEntity = event.getEntityLiving(); if (livingEntity.getActiveEffectsMap() != null && livingEntity.hasEffect(ModEffects.BIG.get())) { EntityDimensions newDims = livingEntity.getDimensions(livingEntity.getPose()).scale(8.0F, 2.0F); try { // using reflection Field field = Entity.class.getDeclaredField("dimensions"); field.setAccessible(true); field.set(livingEntity, newDims); // setting the living entity's EntityDimensions EntityDimensions newEntityDimensions = (EntityDimensions) field.get(livingEntity); livingEntity.setBoundingBox(newEntityDimensions.makeBoundingBox( // setting the living entity's AABB livingEntity.getX(), livingEntity.getY(), livingEntity.getZ() )); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } } The aforementioned drawback is that, when the effect wears off, the living entity still keeps its bigger hitbox until it changes pose (i.e. my player crouching). Given that the EntityEvent.Size event fires whenever an entity changes pose, should I manually fire it with EVENT_BUS::post when that entity's effect wears off? If so, where? I tried manually firing EntityEvent.Size on my overridden removeAttributeModifiers(), but to no avail. Edited May 20, 2022 by LeeCrafts Quote
Alpvax Posted May 20, 2022 Posted May 20, 2022 On 5/20/2022 at 2:10 AM, LeeCrafts said: Field field = Entity.class.getDeclaredField("dimensions"); field.setAccessible(true); Expand You should save this somewhere static, instead of computing it every time. On 5/20/2022 at 2:10 AM, LeeCrafts said: I tried manually firing EntityEvent.Size on my overridden removeAttributeModifiers(), but to no avail. Expand That's not how forge events work. The event doesn't fire to set the size, it fires when the size is changed to allow mods to override it. It is called from the (mojmap) method `Entity#refreshDimensions`, so if you call that method you should restore the entity size. Alternatively, if you don't want to allow other mods to react to the change in size, just recompute the AABB as vanilla does (either setPos, or setBoundingBox(makeBoundingBox())), but I would strongly suggest using the first method. 1 Quote
Luis_ST Posted May 20, 2022 Posted May 20, 2022 On 5/20/2022 at 5:23 PM, Alpvax said: You should save this somewhere static, instead of computing it every time. Expand in addition you need to use ObfuscationReflectionHelper and you need the SRG name of "dimensions" otherwiese it wont work outside of your IDE 1 Quote
LeeCrafts Posted May 20, 2022 Author Posted May 20, 2022 (edited) Solved and it works consistently. Calling Entity::refreshDimensions every tick would be problematic, so I called it only when I needed to. Thank you both for the help! // edit: lol forgot to use SRG name private static final Field dimensionsField = ObfuscationReflectionHelper.findField(Entity.class, "f_19815_"); public ModEvents() { dimensionsField.setAccessible(true); } // this event handler increases the living entity's hitbox size if it has the "big" effect @SubscribeEvent public static void entityHitboxSizeChange(LivingEvent.LivingUpdateEvent event) throws IllegalAccessException { LivingEntity livingEntity = event.getEntityLiving(); if (livingEntity.getActiveEffectsMap() != null) { EntityDimensions entityDimensions = livingEntity.getDimensions(livingEntity.getPose()); boolean isBig = livingEntity.hasEffect(ModEffects.BIG.get()); // Refresh dimensions if the living entity does not have the "big" effect AND its AABB has not changed back to normal. double aabbWidth = roundDigits(livingEntity.getBoundingBox().getXsize(), 4); double bigWidth = roundDigits(8 * entityDimensions.width, 4); if (!isBig && aabbWidth == bigWidth) livingEntity.refreshDimensions(); // change dimensions of living entity using reflections if (isBig) { dimensionsField.set(livingEntity, entityDimensions.scale(8.0F, 2.0F)); EntityDimensions newEntityDimensions = (EntityDimensions) dimensionsField.get(livingEntity); livingEntity.setBoundingBox(newEntityDimensions.makeBoundingBox( livingEntity.getX(), livingEntity.getY(), livingEntity.getZ() )); } } } // little helper function that rounds a double to n digits private static double roundDigits(double num, int digits) { double tenPower = Math.pow(10, digits); return Math.round(num * tenPower) / tenPower; } Edited May 22, 2022 by LeeCrafts Quote
LeeCrafts Posted May 21, 2022 Author Posted May 21, 2022 (edited) (updated the code in my previous comment) The reason why I have been reluctant to use EntityEvent.Size is because whenever I increase the hitbox size of the living entity via setNewSize(), the enlarged hitbox starts jittering whenever it touches a solid block. Would there be anything else I have to do besides call setNewSize()? Edited May 22, 2022 by LeeCrafts Quote
LeeCrafts Posted May 22, 2022 Author Posted May 22, 2022 When I tried using EntityEvent.Size, this is the code: @SubscribeEvent public static void entityHitboxSizeChange(EntityEvent.Size event) { if (event.getEntity() instanceof LivingEntity livingEntity && livingEntity.getActiveEffectsMap() != null) { EntityDimensions entityDimensions = livingEntity.getDimensions(livingEntity.getPose()); if (livingEntity.hasEffect(ModEffects.BIG.get())) { event.setNewSize(entityDimensions.scale(8, 2)); } else { event.setNewSize(entityDimensions); } } } // When I refreshDimensions in removeAttributeModifiers(), the size still does not revert immediately unless the pose changes (i.e. player crouching). // This is under the assumption that refreshDimensions() always triggers an EntityEvent.Size event @Override public void addAttributeModifiers(@NotNull LivingEntity pLivingEntity, @NotNull AttributeMap pAttributeMap, int pAmplifier) { if (!pLivingEntity.level.isClientSide()) { // other stuff ... pLivingEntity.refreshDimensions(); } super.addAttributeModifiers(pLivingEntity, pAttributeMap, pAmplifier); } @Override public void removeAttributeModifiers(@NotNull LivingEntity pLivingEntity, @NotNull AttributeMap pAttributeMap, int pAmplifier) { if (!pLivingEntity.level.isClientSide()) { // other stuff ... pLivingEntity.refreshDimensions(); } super.removeAttributeModifiers(pLivingEntity, pAttributeMap, pAmplifier); } Quote
LeeCrafts Posted May 22, 2022 Author Posted May 22, 2022 Interesting. What could possibly be causing the jittering? Quote
LeeCrafts Posted May 22, 2022 Author Posted May 22, 2022 (edited) Just now I have made my repo private again for privacy reasons, but if you wanna take a look, lemme know if you want it to be public again. Here is my repo Event handler in which the size is changed Custom effect class Note: The effect that I used to make the entity larger is actually called "fat." Edited May 23, 2022 by LeeCrafts Quote
Recommended Posts
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.