diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index e570be48c5..2b3124a0b8 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -285,21 +285,16 @@ this.f_91074_.m_6674_(InteractionHand.MAIN_HAND); } } -@@ -1581,14 +_,20 @@ +@@ -1581,6 +_,8 @@ return false; } else { boolean flag = false; -- switch (this.f_91077_.m_6662_()) { + var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND); -+ HitResult.Type hitType = this.f_91077_.m_6662_(); -+ if (this.f_91077_ instanceof EntityHitResult entityHit) { // Forge: Perform attack range checks here, instead of in GameRenderer#pick, so extended-reach interactions work. -+ if (!f_91074_.canHit(entityHit.m_82443_(), 0)) hitType = HitResult.Type.MISS; // No padding in client code. -+ } + if (!inputEvent.isCanceled()) -+ switch(hitType) { + switch (this.f_91077_.m_6662_()) { case ENTITY: this.f_91072_.m_105223_(this.f_91074_, ((EntityHitResult)this.f_91077_).m_82443_()); - break; +@@ -1588,7 +_,7 @@ case BLOCK: BlockHitResult blockhitresult = (BlockHitResult)this.f_91077_; BlockPos blockpos = blockhitresult.m_82425_(); @@ -331,14 +326,7 @@ ItemStack itemstack = this.f_91074_.m_21120_(interactionhand); if (!itemstack.m_246617_(this.f_91073_.m_246046_())) { return; -@@ -1632,13 +_,14 @@ - return; - } - -+ if(!this.f_91074_.canInteractWith(entityhitresult.m_82443_(), 0)) break; //Forge: Entity may be traced via attack range, but the player may not have sufficient reach. No padding in client code. - InteractionResult interactionresult = this.f_91072_.m_105230_(this.f_91074_, entity, entityhitresult, interactionhand); - if (!interactionresult.m_19077_()) { - interactionresult = this.f_91072_.m_105226_(this.f_91074_, entity, interactionhand); +@@ -1638,7 +_,7 @@ } if (interactionresult.m_19077_()) { diff --git a/patches/minecraft/net/minecraft/client/gui/Gui.java.patch b/patches/minecraft/net/minecraft/client/gui/Gui.java.patch index 7ef017bfa5..919977f651 100644 --- a/patches/minecraft/net/minecraft/client/gui/Gui.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/Gui.java.patch @@ -1,13 +1,5 @@ --- a/net/minecraft/client/gui/Gui.java +++ b/net/minecraft/client/gui/Gui.java -@@ -374,6 +_,7 @@ - if (this.f_92986_.f_91076_ != null && this.f_92986_.f_91076_ instanceof LivingEntity && f >= 1.0F) { - flag = this.f_92986_.f_91074_.m_36333_() > 5.0F; - flag &= this.f_92986_.f_91076_.m_6084_(); -+ flag &= this.f_92986_.f_91074_.canHit(this.f_92986_.f_91076_, 0); - } - - int j = this.f_92978_ / 2 - 7 + 16; @@ -428,6 +_,10 @@ for(MobEffectInstance mobeffectinstance : Ordering.natural().reverse().sortedCopy(collection)) { diff --git a/patches/minecraft/net/minecraft/client/multiplayer/MultiPlayerGameMode.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/MultiPlayerGameMode.java.patch index 66f7153dec..6355d0027c 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/MultiPlayerGameMode.java.patch +++ b/patches/minecraft/net/minecraft/client/multiplayer/MultiPlayerGameMode.java.patch @@ -84,7 +84,7 @@ public float m_105286_() { - return this.f_105197_.m_46408_() ? 5.0F : 4.5F; -+ return (float) this.f_105189_.f_91074_.getReachDistance(); ++ return (float) this.f_105189_.f_91074_.getBlockReach(); } public void m_105287_() { diff --git a/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch index b3f876abef..6ebd3945f9 100644 --- a/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch @@ -17,37 +17,49 @@ } catch (IOException ioexception) { list1.forEach((p_172729_) -> { p_172729_.getFirst().close(); -@@ -678,19 +_,21 @@ +@@ -673,12 +_,13 @@ + this.f_109059_.m_91307_().m_6180_("pick"); + this.f_109059_.f_91076_ = null; + double d0 = (double)this.f_109059_.f_91072_.m_105286_(); +- this.f_109059_.f_91077_ = entity.m_19907_(d0, p_109088_, false); ++ double entityReach = this.f_109059_.f_91074_.getEntityReach(); // Note - MC-76493 - We must validate players cannot click-through objects. ++ this.f_109059_.f_91077_ = entity.m_19907_(Math.max(d0, entityReach), p_109088_, false); // Run pick() with the max of the two, so we can prevent click-through. + Vec3 vec3 = entity.m_20299_(p_109088_); boolean flag = false; int i = 3; double d1 = d0; -+ double atkRange = this.f_109059_.f_91074_.getAttackRange(); - if (this.f_109059_.f_91072_.m_105291_()) { -- d1 = 6.0D; -+ d1 = Math.max(d0, atkRange); +- if (this.f_109059_.f_91072_.m_105291_()) { ++ if (false && this.f_109059_.f_91072_.m_105291_()) { + d1 = 6.0D; d0 = d1; } else { -- if (d0 > 3.0D) { -+ if (d0 > atkRange) { - flag = true; - } +@@ -688,10 +_,19 @@ d0 = d0; -+ d0 = d1 = Math.max(d0, atkRange); // Pick entities with the max of the reach distance and attack range. } ++ d0 = d1 = Math.max(d0, entityReach); // Pick entities with the max of both for the same reason. d1 *= d1; - if (this.f_109059_.f_91077_ != null) { -+ if (this.f_109059_.f_91077_ != null && this.f_109059_.f_91077_.m_6662_() != HitResult.Type.MISS) { // Add != MISS to ensure Attack Range is not clamped at the value of Reach Distance. ++ // If we picked a block, we need to ignore entities past that block. Added != MISS check to not truncate on failed picks. ++ // Also fixes MC-250858 ++ if (this.f_109059_.f_91077_ != null && this.f_109059_.f_91077_.m_6662_() != HitResult.Type.MISS) { d1 = this.f_109059_.f_91077_.m_82450_().m_82557_(vec3); ++ double blockReach = this.f_109059_.f_91074_.getBlockReach(); ++ // Discard the result as a miss if it is outside the block reach. ++ if (d1 > blockReach * blockReach) { ++ Vec3 pos = this.f_109059_.f_91077_.m_82450_(); ++ this.f_109059_.f_91077_ = BlockHitResult.m_82426_(pos, Direction.m_122366_(vec3.f_82479_, vec3.f_82480_, vec3.f_82481_), BlockPos.m_274446_(pos)); ++ } } + Vec3 vec31 = entity.m_20252_(1.0F); @@ -705,7 +_,7 @@ Entity entity1 = entityhitresult.m_82443_(); Vec3 vec33 = entityhitresult.m_82450_(); double d2 = vec3.m_82557_(vec33); - if (flag && d2 > 9.0D) { -+ if (false && flag && d2 > 9.0D) { //Forge: Always keep the entity result to allow for extended reach interactions. ++ if (d2 > d1 || d2 > entityReach * entityReach) { // Discard if the result is behind a block, or past the entity reach max. The var "flag" no longer has a use. this.f_109059_.f_91077_ = BlockHitResult.m_82426_(vec33, Direction.m_122366_(vec31.f_82479_, vec31.f_82480_, vec31.f_82481_), BlockPos.m_274446_(vec33)); } else if (d2 < d1 || this.f_109059_.f_91077_ == null) { this.f_109059_.f_91077_ = entityhitresult; diff --git a/patches/minecraft/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/patches/minecraft/net/minecraft/server/level/ServerPlayerGameMode.java.patch index 534291458e..6938c835cf 100644 --- a/patches/minecraft/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/patches/minecraft/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -9,7 +9,7 @@ + if (event.isCanceled() || (!this.m_9295_() && event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY)) { + return; + } -+ if (!this.f_9245_.canInteractWith(p_215120_, 1)) { ++ if (!this.f_9245_.canReach(p_215120_, 1.5)) { // Vanilla check is eye-to-center distance < 6, so padding is 6 - 4.5 = 1.5 this.m_215125_(p_215120_, false, p_215124_, "too far"); } else if (p_215120_.m_123342_() >= p_215123_) { this.f_9245_.f_8906_.m_9829_(new ClientboundBlockUpdatePacket(p_215120_, this.f_9244_.m_8055_(p_215120_))); diff --git a/patches/minecraft/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/patches/minecraft/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index ef3a139d77..3f69a2b4c5 100644 --- a/patches/minecraft/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/patches/minecraft/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -6,8 +6,8 @@ private static final int f_143608_ = 15000; + /** + * Forge: Deprecated in favor of range/reach attributes. -+ * @see net.minecraftforge.common.ForgeMod#REACH_DISTANCE -+ * @see net.minecraftforge.common.ForgeMod#ATTACK_RANGE ++ * @see net.minecraftforge.common.ForgeMod#BLOCK_REACH ++ * @see net.minecraftforge.common.ForgeMod#ENTITY_REACH + */ + @Deprecated public static final double f_215198_ = Mth.m_144952_(6.0D); @@ -39,7 +39,7 @@ BlockPos blockpos = blockhitresult.m_82425_(); Vec3 vec31 = Vec3.m_82512_(blockpos); - if (!(this.f_9743_.m_146892_().m_82557_(vec31) > f_215198_)) { -+ if (this.f_9743_.canInteractWith(blockpos, 3)) { ++ if (this.f_9743_.canReach(blockpos, 1.5)) { // Vanilla uses eye-to-center distance < 6, which implies a padding of 1.5 Vec3 vec32 = vec3.m_82546_(vec31); double d0 = 1.0000001D; if (Math.abs(vec32.m_7096_()) < 1.0000001D && Math.abs(vec32.m_7098_()) < 1.0000001D && Math.abs(vec32.m_7094_()) < 1.0000001D) { @@ -68,18 +68,15 @@ this.m_243086_(playerchatmessage1); }, p_248212_); }); -@@ -1435,9 +_,10 @@ +@@ -1435,7 +_,7 @@ } AABB aabb = entity.m_20191_(); - if (aabb.m_272282_(this.f_9743_.m_146892_()) < f_215198_) { -+ if (true) { //Forge: Perform distance checks below since interactions and attacks differ. ++ if (this.f_9743_.canReach(entity, 3)) { // Vanilla padding is 3.0 (distSq < 6.0 * 6.0) p_9866_.m_179617_(new ServerboundInteractPacket.Handler() { private void m_143678_(InteractionHand p_143679_, ServerGamePacketListenerImpl.EntityInteraction p_143680_) { -+ if(!ServerGamePacketListenerImpl.this.f_9743_.canInteractWith(entity, 1.5D)) return; //Forge: If the entity cannot be reached, do nothing. Original check was dist < 6, range is 4.5, so vanilla used padding=1.5 ItemStack itemstack = ServerGamePacketListenerImpl.this.f_9743_.m_21120_(p_143679_); - if (itemstack.m_246617_(serverlevel.m_246046_())) { - ItemStack itemstack1 = itemstack.m_41777_(); @@ -1458,6 +_,8 @@ public void m_142143_(InteractionHand p_143682_, Vec3 p_143683_) { @@ -89,15 +86,6 @@ return p_143687_.m_7111_(p_143686_, p_143683_, p_143688_); }); } -@@ -1466,6 +_,8 @@ - if (!(entity instanceof ItemEntity) && !(entity instanceof ExperienceOrb) && !(entity instanceof AbstractArrow) && entity != ServerGamePacketListenerImpl.this.f_9743_) { - ItemStack itemstack = ServerGamePacketListenerImpl.this.f_9743_.m_21120_(InteractionHand.MAIN_HAND); - if (itemstack.m_246617_(serverlevel.m_246046_())) { -+ //Forge: Perform attack range check. Original check was dist < 6, range is 3, so vanilla used padding=3 -+ if(ServerGamePacketListenerImpl.this.f_9743_.canHit(entity, 3)) - ServerGamePacketListenerImpl.this.f_9743_.m_5706_(entity); - } - } else { @@ -1670,6 +_,7 @@ } diff --git a/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch b/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch index 77d9ab128a..0e4c49cc25 100644 --- a/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch @@ -25,7 +25,7 @@ public static AttributeSupplier.Builder m_36340_() { - return LivingEntity.m_21183_().m_22268_(Attributes.f_22281_, 1.0D).m_22268_(Attributes.f_22279_, (double)0.1F).m_22266_(Attributes.f_22283_).m_22266_(Attributes.f_22286_); -+ return LivingEntity.m_21183_().m_22268_(Attributes.f_22281_, 1.0D).m_22268_(Attributes.f_22279_, (double) 0.1F).m_22266_(Attributes.f_22283_).m_22266_(Attributes.f_22286_).m_22266_(net.minecraftforge.common.ForgeMod.REACH_DISTANCE.get()).m_22266_(Attributes.f_22282_).m_22266_(net.minecraftforge.common.ForgeMod.ATTACK_RANGE.get()); ++ return LivingEntity.m_21183_().m_22268_(Attributes.f_22281_, 1.0D).m_22268_(Attributes.f_22279_, (double) 0.1F).m_22266_(Attributes.f_22283_).m_22266_(Attributes.f_22286_).m_22266_(net.minecraftforge.common.ForgeMod.BLOCK_REACH.get()).m_22266_(Attributes.f_22282_).m_22266_(net.minecraftforge.common.ForgeMod.ENTITY_REACH.get()); } protected void m_8097_() { @@ -252,14 +252,15 @@ } float f4 = 0.0F; -@@ -1120,8 +_,8 @@ +@@ -1120,8 +_,9 @@ if (flag3) { float f3 = 1.0F + EnchantmentHelper.m_44821_(this) * f; - for(LivingEntity livingentity : this.f_19853_.m_45976_(LivingEntity.class, p_36347_.m_20191_().m_82377_(1.0D, 0.25D, 1.0D))) { - if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.m_20280_(livingentity) < 9.0D) { + for(LivingEntity livingentity : this.f_19853_.m_45976_(LivingEntity.class, this.m_21120_(InteractionHand.MAIN_HAND).getSweepHitBox(this, p_36347_))) { -+ if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.canHit(livingentity, 0)) { // Original check was dist < 3, range is 3, so vanilla used padding=0 ++ double entityReachSq = Mth.m_144952_(this.getEntityReach()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. ++ if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.m_20280_(livingentity) < entityReachSq) { livingentity.m_147240_((double)0.4F, (double)Mth.m_14031_(this.m_146908_() * ((float)Math.PI / 180F)), (double)(-Mth.m_14089_(this.m_146908_() * ((float)Math.PI / 180F)))); livingentity.m_6469_(this.m_269291_().m_269075_(this), f3); } diff --git a/patches/minecraft/net/minecraft/world/item/Item.java.patch b/patches/minecraft/net/minecraft/world/item/Item.java.patch index 9353707508..15fa5f1e89 100644 --- a/patches/minecraft/net/minecraft/world/item/Item.java.patch +++ b/patches/minecraft/net/minecraft/world/item/Item.java.patch @@ -112,7 +112,7 @@ float f7 = f2 * f4; - double d0 = 5.0D; - Vec3 vec31 = vec3.m_82520_((double)f6 * 5.0D, (double)f5 * 5.0D, (double)f7 * 5.0D); -+ double d0 = p_41437_.getReachDistance(); ++ double d0 = p_41437_.getBlockReach(); + Vec3 vec31 = vec3.m_82520_((double)f6 * d0, (double)f5 * d0, (double)f7 * d0); return p_41436_.m_45547_(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, p_41438_, p_41437_)); } diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 3063bb5517..cbb1f268b0 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -145,30 +145,45 @@ public class ForgeMod ArgumentTypeInfos.registerByClass(ModIdArgument.class, SingletonArgumentInfo.contextFree(ModIdArgument::modIdArgument))); - public static final RegistryObject SWIM_SPEED = ATTRIBUTES.register("swim_speed", () -> new RangedAttribute("forge.swimSpeed", 1.0D, 0.0D, 1024.0D).setSyncable(true)); - public static final RegistryObject NAMETAG_DISTANCE = ATTRIBUTES.register("nametag_distance", () -> new RangedAttribute("forge.nameTagDistance", 64.0D, 0.0D, 64.0).setSyncable(true)); + public static final RegistryObject SWIM_SPEED = ATTRIBUTES.register("swim_speed", () -> new RangedAttribute("forge.swim_speed", 1.0D, 0.0D, 1024.0D).setSyncable(true)); + public static final RegistryObject NAMETAG_DISTANCE = ATTRIBUTES.register("nametag_distance", () -> new RangedAttribute("forge.name_tag_distance", 64.0D, 0.0D, 64.0).setSyncable(true)); public static final RegistryObject ENTITY_GRAVITY = ATTRIBUTES.register("entity_gravity", () -> new RangedAttribute("forge.entity_gravity", 0.08D, -8.0D, 8.0D).setSyncable(true)); /** - * Reach Distance represents the distance at which a player may interact with the world. The default is 4.5 blocks. Players in creative mode have an additional 0.5 blocks of reach distance. - * @see IForgePlayer#getReachDistance() - * @see IForgePlayer#canInteractWith(BlockPos, double) - * @see IForgePlayer#canInteractWith(Entity, double) + * Reach Distance represents the distance at which a player may interact with the world. The default is 4.5 blocks. Players in creative mode have an additional 0.5 blocks of block reach. + * @see IForgePlayer#getBlockReach() + * @see IForgePlayer#canReach(BlockPos, double) */ - public static final RegistryObject REACH_DISTANCE = ATTRIBUTES.register("reach_distance", () -> new RangedAttribute("generic.reachDistance", 4.5D, 0.0D, 1024.0D).setSyncable(true)); + public static final RegistryObject BLOCK_REACH = ATTRIBUTES.register("block_reach", () -> new RangedAttribute("forge.block_reach", 4.5D, 0.0D, 1024.0D).setSyncable(true)); /** - * Attack Range represents the distance at which a player may attack an entity. The default is 3 blocks. Players in creative mode have an additional 3 blocks of attack reach. - * @see IForgePlayer#getAttackRange() - * @see IForgePlayer#canHit(Entity, double) + * TODO: Remove + * @deprecated - use {@link #BLOCK_REACH} */ - public static final RegistryObject ATTACK_RANGE = ATTRIBUTES.register("attack_range", () -> new RangedAttribute("generic.attack_range", 3.0D, 0.0D, 1024.0D).setSyncable(true)); + @Deprecated(forRemoval = true, since = "1.19.4") + public static final RegistryObject REACH_DISTANCE = BLOCK_REACH; + + /** + * Attack Range represents the distance at which a player may attack an entity. The default is 3 blocks. Players in creative mode have an additional 3 blocks of entity reach. + * The default of 3.0 is technically considered a bug by Mojang - see MC-172289 and MC-92484. However, updating this value would allow for longer-range attacks on vanilla servers, which makes some people mad. + * @see IForgePlayer#getEntityReach() + * @see IForgePlayer#canReach(Entity, double) + * @see IForgePlayer#canReach(Vec3, double) + */ + public static final RegistryObject ENTITY_REACH = ATTRIBUTES.register("entity_reach", () -> new RangedAttribute("forge.entity_reach", 3.0D, 0.0D, 1024.0D).setSyncable(true)); + + /** + * TODO: Remove + * @deprecated - use {@link #ENTITY_REACH} + */ + @Deprecated(forRemoval = true, since = "1.19.4") + public static final RegistryObject ATTACK_RANGE = ENTITY_REACH; /** * Step Height Addition modifies the amount of blocks an entity may walk up without jumping. * @see IForgeEntity#getStepHeight() */ - public static final RegistryObject STEP_HEIGHT_ADDITION = ATTRIBUTES.register("step_height_addition", () -> new RangedAttribute("forge.stepHeight", 0.0D, -512.0D, 512.0D).setSyncable(true)); + public static final RegistryObject STEP_HEIGHT_ADDITION = ATTRIBUTES.register("step_height_addition", () -> new RangedAttribute("forge.step_height", 0.0D, -512.0D, 512.0D).setSyncable(true)); /** * Noop biome modifier. Can be used in a biome modifier json with "type": "forge:none". @@ -461,6 +476,10 @@ public class ForgeMod MinecraftForge.EVENT_BUS.addListener(this::registerPermissionNodes); ForgeRegistries.ITEMS.tags().addOptionalTagDefaults(Tags.Items.ENCHANTING_FUELS, Set.of(ForgeRegistries.ITEMS.getDelegateOrThrow(Items.LAPIS_LAZULI))); + + // TODO: Remove when addAlias becomes proper API, as this should be done in the DR's above. + addAlias(ForgeRegistries.ATTRIBUTES, new ResourceLocation("forge", "reach_distance"), new ResourceLocation("forge", "block_reach")); + addAlias(ForgeRegistries.ATTRIBUTES, new ResourceLocation("forge", "attack_range"), new ResourceLocation("forge", "entity_reach")); } public void preInit(FMLCommonSetupEvent evt) @@ -624,4 +643,14 @@ public class ForgeMod { event.addNodes(USE_SELECTORS_PERMISSION); } + + /** + * TODO: Remove when {@link ForgeRegistry#addAlias(ResourceLocation, ResourceLocation)} is elevated to {@link IForgeRegistry}. + */ + @Deprecated(forRemoval = true, since = "1.19.3") + private static void addAlias(IForgeRegistry registry, ResourceLocation from, ResourceLocation to) + { + ForgeRegistry fReg = (ForgeRegistry) registry; + fReg.addAlias(from, to); + } } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgePlayer.java b/src/main/java/net/minecraftforge/common/extensions/IForgePlayer.java index 2bcdfc6bd1..f0fb15874c 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgePlayer.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgePlayer.java @@ -5,11 +5,12 @@ package net.minecraftforge.common.extensions; -import java.util.Optional; - import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.ForgeMod; @@ -22,74 +23,121 @@ public interface IForgePlayer } /** - * The attack range is increased by 3 for creative players, unless it is currently zero, which disables attacks. - * @return The attack range of this player. + * The entity reach is increased by 3 for creative players, unless it is currently zero, which disables attacks and entity interactions. + * @return The entity reach of this player. */ + default double getEntityReach() + { + double range = self().getAttributeValue(ForgeMod.ENTITY_REACH.get()); + return range == 0 ? 0 : range + (self().isCreative() ? 3 : 0); + } + + /** + * @deprecated Use {@link #getEntityReach()} + */ + @Deprecated(forRemoval = true, since = "1.19.4") default double getAttackRange() { - double range = self().getAttributeValue(ForgeMod.ATTACK_RANGE.get()); - return range == 0 ? 0 : range + (self().isCreative() ? 3 : 0); + return this.getEntityReach(); } /** * The reach distance is increased by 0.5 for creative players, unless it is currently zero, which disables interactions. * @return The reach distance of this player. */ - default double getReachDistance() + default double getBlockReach() { - double reach = self().getAttributeValue(ForgeMod.REACH_DISTANCE.get()); + double reach = self().getAttributeValue(ForgeMod.BLOCK_REACH.get()); return reach == 0 ? 0 : reach + (self().isCreative() ? 0.5 : 0); } /** - * Checks if the player can attack the passed entity.
- * On the server, additional leniency is added to account for movement/lag. + * @deprecated use {@link #getBlockReach()} + */ + @Deprecated(forRemoval = true, since = "1.19.4") + default double getReachDistance() + { + return this.getBlockReach(); + } + + /** + * Checks if the player can reach an entity by targeting the passed vector.
+ * On the server, additional padding is added to account for movement/lag. + * @param vec The vector being range-checked. + * @param padding Extra validation distance. + * @return If the player can attack the entity. + * @apiNote Do not use for block checks, as this method uses {@link #getEntityReach()} + */ + default boolean canReach(Vec3 entityHitVec, double padding) + { + return self().getEyePosition().closerThan(entityHitVec, getEntityReach() + padding); + } + + /** + * Checks if the player can reach an entity.
+ * On the server, additional padding is added to account for movement/lag. * @param entity The entity being range-checked. * @param padding Extra validation distance. * @return If the player can attack the passed entity. + * @apiNote Prefer using {@link #canReach(Vec3, double)} if you have a {@link HitResult} available. */ - default boolean canHit(Entity entity, double padding) // Do not rename to canAttack - will conflict with LivingEntity#canAttack + default boolean canReach(Entity entity, double padding) { - return isCloseEnough(entity, getAttackRange() + padding); + return isCloseEnough(entity, getEntityReach() + padding); } /** - * Checks if the player can reach (right-click) the passed entity.
- * On the server, additional leniency is added to account for movement/lag. - * @param entity The entity being range-checked. - * @param padding Extra validation distance. - * @return If the player can interact with the passed entity. + * @deprecated use {@link #canReach(Entity, double)}h */ + @Deprecated(forRemoval = true, since = "1.19.4") + default boolean canHit(Entity entity, double padding) + { + return canReach(entity, padding); + } + + /** + * @deprecated use {@link #canReach(Entity, double)}h + */ + @Deprecated(forRemoval = true, since = "1.19.4") default boolean canInteractWith(Entity entity, double padding) { - return isCloseEnough(entity, getReachDistance() + padding); + return canReach(entity, padding); } /** - * Utility check to see if the player is close enough to a target entity. - * @param entity The entity being checked against - * @param dist The max distance allowed - * @return If the eye-to-center distance between this player and the passed entity is less than dist. - */ - default boolean isCloseEnough(Entity entity, double dist) - { - Vec3 eye = self().getEyePosition(); - Vec3 targetCenter = entity.getPosition(1.0F).add(0, entity.getBbHeight() / 2, 0); - Optional hit = entity.getBoundingBox().clip(eye, targetCenter); //This hit should almost always be present, but we have a fallback just in case. It likely indicates lag if it is not present. - return (hit.isPresent() ? eye.distanceToSqr(hit.get()) : self().distanceToSqr(entity)) < dist * dist; - } - - /** - * Checks if the player can reach (right-click) a block.
- * On the server, additional leniency is added to account for movement/lag. + * Checks if the player can reach a block.
+ * On the server, additional padding is added to account for movement/lag. * @param pos The position being range-checked. * @param padding Extra validation distance. * @return If the player can interact with this location. */ + default boolean canReach(BlockPos pos, double padding) + { + double reach = this.getBlockReach() + padding; + return self().getEyePosition().distanceToSqr(Vec3.atCenterOf(pos)) < reach * reach; + } + + /** + * @deprecated use {@link #canReach(BlockPos, double)} + */ + @Deprecated(forRemoval = true, since = "1.19.4") default boolean canInteractWith(BlockPos pos, double padding) { - double reach = getReachDistance() + padding; - return self().getEyePosition().distanceToSqr(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D) < reach * reach; + return canReach(pos, padding); + } + + /** + * Utility check to see if the player is close enough to a target entity. Uses "eye-to-closest-corner" checks. + * @param entity The entity being checked against + * @param dist The max distance allowed + * @return If the eye-to-center distance between this player and the passed entity is less than dist. + * @implNote This method inflates the bounding box by the pick radius, which differs from vanilla. But vanilla doesn't use the pick radius, the only entity with > 0 is AbstractHurtingProjectile. + */ + default boolean isCloseEnough(Entity entity, double dist) + { + Vec3 eye = self().getEyePosition(); + AABB aabb = entity.getBoundingBox().inflate(entity.getPickRadius()); + return aabb.distanceToSqr(eye) < dist * dist; } } diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java index 1846aa35b0..b3d11d4cb1 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java @@ -45,9 +45,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +@ApiStatus.Internal public class ForgeRegistry implements IForgeRegistryInternal, IForgeRegistryModifiable { public static Marker REGISTRIES = MarkerManager.getMarker("REGISTRIES"); @@ -480,25 +482,33 @@ public class ForgeRegistry implements IForgeRegistryInternal, IForgeRegist return ret; } - void addAlias(ResourceLocation from, ResourceLocation to) + /** + * Adds an alias that maps from the name specified by src to the name specified by dst.

+ * Any registry lookups that target the first name will resolve as the second name, if the first name is not present. + * @param src The source registry name to alias from. + * @param dst The target registry name to alias to. + * + * TODO: Add as public API in IForgeRegistry and DeferredRegister. + */ + public void addAlias(ResourceLocation src, ResourceLocation dst) { if (this.isLocked()) - throw new IllegalStateException(String.format(Locale.ENGLISH, "Attempted to register the alias %s -> %s to late", from, to)); + throw new IllegalStateException(String.format(Locale.ENGLISH, "Attempted to register the alias %s -> %s too late", src, dst)); - if (from.equals(to)) + if (src.equals(dst)) { - LOGGER.warn(REGISTRIES, "Registry {} Ignoring invalid alias: {} -> {}", this.name, from, to); + LOGGER.warn(REGISTRIES, "Registry {} Ignoring invalid alias: {} -> {}", this.name, src, dst); return; } - this.aliases.put(from, to); - LOGGER.trace(REGISTRIES,"Registry {} alias: {} -> {}", this.name, from, to); + this.aliases.put(src, dst); + LOGGER.trace(REGISTRIES,"Registry {} alias: {} -> {}", this.name, src, dst); } void addDummy(ResourceLocation key) { if (this.isLocked()) - throw new IllegalStateException(String.format(Locale.ENGLISH, "Attempted to register the dummy %s to late", key)); + throw new IllegalStateException(String.format(Locale.ENGLISH, "Attempted to register the dummy %s too late", key)); this.dummies.add(key); LOGGER.trace(REGISTRIES,"Registry {} dummy: {}", this.name, key); } @@ -647,8 +657,14 @@ public class ForgeRegistry implements IForgeRegistryInternal, IForgeRegist this.max = from.max; this.min = from.min; */ - this.aliases.clear(); - from.aliases.forEach(this::addAlias); + // Aliases from the active registry take priority over those from the staged (loaded) registry. + for (var entry : from.aliases.entrySet()) + { + if (!this.aliases.containsKey(entry.getKey())) + { + this.aliases.put(entry.getKey(), entry.getValue()); + } + } this.ids.clear(); this.names.clear(); diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index c3f61062d1..6f2db3e4e1 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -202,17 +202,12 @@ "forge.controlsgui.alt": "ALT + %s", "forge.container.enchant.limitedEnchantability": "Limited Enchantability", - "attribute.name.forge.swim_speed": "Swim Speed", - "attribute.name.forge.nametag_distance": "Nametag Render Distance", - "attribute.name.forge.entity_gravity": "Entity Gravity", - "attribute.name.generic.reach_distance": "Reach Distance", - "attribute.name.generic.attack_range": "Attack Range", - "forge.swimSpeed": "Swim Speed", - "forge.nameTagDistance": "Nametag Render Distance", - "forge.entity_gravity": "Entity Gravity", - "generic.reachDistance": "Reach Distance", - "generic.attack_range": "Attack Range", - "forge.stepHeight": "Step Height", + "forge.swim_speed": "Swim Speed", + "forge.name_tag_distance": "Nametag Render Distance", + "forge.entity_gravity": "Gravity", + "forge.block_reach": "Block Reach", + "forge.entity_reach": "Entity Reach", + "forge.step_height": "Step Height", "fluid_type.minecraft.milk": "Milk", "fluid_type.minecraft.flowing_milk": "Milk",