From 510b8187c7b634935cce5b22f4e86d1421dba3e4 Mon Sep 17 00:00:00 2001 From: Hugo Manrique Date: Mon, 23 Jul 2018 14:22:26 +0200 Subject: [PATCH] Vanished players don't have rights --- .../entity/projectile/Projectile.java.patch | 28 ++++-- .../minecraft/world/item/BlockItem.java.patch | 7 +- .../minecraft/world/level/Level.java.patch | 86 ++++++++++++++----- .../craftbukkit/event/CraftEventFactory.java | 8 ++ 4 files changed, 97 insertions(+), 32 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch index 5e34291d60..fa8233aaf8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -43,12 +43,10 @@ iprojectile.shootFromRotation(shooter, shooter.getXRot(), shooter.getYRot(), roll, power, divergence); }); } -@@ -209,13 +222,36 @@ - public static T spawnProjectile(T projectile, ServerLevel world, ItemStack projectileStack) { - return Projectile.spawnProjectile(projectile, world, projectileStack, (iprojectile) -> { +@@ -211,11 +224,34 @@ }); -+ } -+ + } + + // Paper start - delayed projectile spawning + public record Delayed( + T projectile, @@ -66,9 +64,9 @@ + this.attemptSpawn(); + return projectile(); + } - } ++ } + // Paper end - delayed projectile spawning - ++ public static T spawnProjectile(T projectile, ServerLevel world, ItemStack projectileStack, Consumer beforeSpawn) { + // Paper start - delayed projectile spawning + return spawnProjectileDelayed(projectile, world, projectileStack, beforeSpawn).spawn(); @@ -113,3 +111,19 @@ BlockState iblockdata = this.level().getBlockState(blockHitResult.getBlockPos()); iblockdata.onProjectileHit(this.level(), iblockdata, blockHitResult, this); +@@ -320,6 +372,15 @@ + } else { + Entity entity1 = this.getOwner(); + ++ // Paper start - Cancel hit for vanished players ++ if (entity1 instanceof net.minecraft.server.level.ServerPlayer && entity instanceof net.minecraft.server.level.ServerPlayer) { ++ org.bukkit.entity.Player collided = (org.bukkit.entity.Player) entity.getBukkitEntity(); ++ org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) entity1.getBukkitEntity(); ++ if (!shooter.canSee(collided)) { ++ return false; ++ } ++ } ++ // Paper end - Cancel hit for vanished players + return entity1 == null || this.leftOwner || !entity1.isPassengerOfSameVehicle(entity); + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch index a688ebb0e3..971e24dbd7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch @@ -64,12 +64,13 @@ world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1)); itemstack.consume(1, entityhuman); return InteractionResult.SUCCESS; -@@ -144,8 +167,15 @@ +@@ -144,8 +167,16 @@ protected boolean canPlace(BlockPlaceContext context, BlockState state) { Player entityhuman = context.getPlayer(); CollisionContext voxelshapecollision = entityhuman == null ? CollisionContext.empty() : CollisionContext.of(entityhuman); + // CraftBukkit start - store default return -+ boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && context.getLevel().isUnobstructed(state, context.getClickedPos(), voxelshapecollision); ++ Level world = context.getLevel(); // Paper - Cancel hit for vanished players ++ boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && world.checkEntityCollision(state, entityhuman, voxelshapecollision, context.getClickedPos(), true); // Paper - Cancel hit for vanished players + org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; - return (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && context.getLevel().isUnobstructed(state, context.getClickedPos(), voxelshapecollision); @@ -81,7 +82,7 @@ } protected boolean mustSurvive() { -@@ -178,7 +208,7 @@ +@@ -178,7 +209,7 @@ return false; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index d5fcf78af4..5ed5e0770d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -150,7 +150,7 @@ } }; } else { -@@ -145,11 +219,49 @@ +@@ -145,13 +219,90 @@ } this.thread = Thread.currentThread(); @@ -204,8 +204,49 @@ + this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); } ++ // Paper start - Cancel hit for vanished players ++ // ret true if no collision ++ public final boolean checkEntityCollision(BlockState data, Entity source, net.minecraft.world.phys.shapes.CollisionContext voxelshapedcollision, ++ BlockPos position, boolean checkCanSee) { ++ // Copied from IWorldReader#a(IBlockData, BlockPosition, VoxelShapeCollision) & EntityAccess#a(Entity, VoxelShape) ++ net.minecraft.world.phys.shapes.VoxelShape voxelshape = data.getCollisionShape(this, position, voxelshapedcollision); ++ if (voxelshape.isEmpty()) { ++ return true; ++ } ++ ++ voxelshape = voxelshape.move((double) position.getX(), (double) position.getY(), (double) position.getZ()); ++ if (voxelshape.isEmpty()) { ++ return true; ++ } ++ ++ List entities = this.getEntities(null, voxelshape.bounds()); ++ for (int i = 0, len = entities.size(); i < len; ++i) { ++ Entity entity = entities.get(i); ++ ++ if (checkCanSee && source instanceof net.minecraft.server.level.ServerPlayer && entity instanceof net.minecraft.server.level.ServerPlayer ++ && !((net.minecraft.server.level.ServerPlayer) source).getBukkitEntity().canSee(((net.minecraft.server.level.ServerPlayer) entity).getBukkitEntity())) { ++ continue; ++ } ++ ++ // !entity1.dead && entity1.i && (entity == null || !entity1.x(entity)); ++ // elide the last check since vanilla calls with entity = null ++ // only we care about the source for the canSee check ++ if (entity.isRemoved() || !entity.blocksBuilding) { ++ continue; ++ } ++ ++ if (net.minecraft.world.phys.shapes.Shapes.joinIsNotEmpty(voxelshape, net.minecraft.world.phys.shapes.Shapes.create(entity.getBoundingBox()), net.minecraft.world.phys.shapes.BooleanOp.AND)) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - Cancel hit for vanished players @Override -@@ -163,6 +275,13 @@ + public boolean isClientSide() { + return this.isClientSide; +@@ -163,6 +314,13 @@ return null; } @@ -219,7 +260,7 @@ public boolean isInWorldBounds(BlockPos pos) { return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos); } -@@ -179,18 +298,73 @@ +@@ -179,18 +337,73 @@ return y < -20000000 || y >= 20000000; } @@ -237,7 +278,7 @@ + // Paper start - if loaded @Nullable - @Override ++ @Override + public final ChunkAccess getChunkIfLoadedImmediately(int x, int z) { + return ((ServerLevel)this).chunkSource.getChunkAtIfLoadedImmediately(x, z); + } @@ -269,7 +310,7 @@ + return chunk == null ? null : chunk.getFluidState(blockposition); + } + -+ @Override + @Override + public final boolean hasChunkAt(BlockPos pos) { + return getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4) != null; // Paper - Perf: Optimize Level.hasChunkAt(BlockPosition)Z + } @@ -296,7 +337,7 @@ ChunkAccess ichunkaccess = this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, create); if (ichunkaccess == null && create) { -@@ -207,6 +381,18 @@ +@@ -207,6 +420,18 @@ @Override public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { @@ -315,7 +356,7 @@ if (this.isOutsideBuildHeight(pos)) { return false; } else if (!this.isClientSide && this.isDebug()) { -@@ -214,44 +400,124 @@ +@@ -214,45 +439,125 @@ } else { LevelChunk chunk = this.getChunkAt(pos); Block block = state.getBlock(); @@ -400,10 +441,10 @@ + // CraftBukkit end + return true; -+ } -+ } -+ } -+ + } + } + } + + // CraftBukkit start - Split off from above in order to directly send client and physic updates + public void notifyAndUpdatePhysics(BlockPos blockposition, LevelChunk chunk, BlockState oldBlock, BlockState newBlock, BlockState actualBlock, int i, int j) { + BlockState iblockdata = newBlock; @@ -423,7 +464,7 @@ + if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) { + this.updateNeighbourForOutputSignal(blockposition, newBlock.getBlock()); + } - } ++ } + + if ((i & 16) == 0 && j > 0) { + int k = i & -34; @@ -449,13 +490,14 @@ + this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); + } + // CraftBukkit end - } - } ++ } ++ } + // CraftBukkit end - ++ public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {} -@@ -340,10 +606,18 @@ + @Override +@@ -340,10 +645,18 @@ @Override public BlockState getBlockState(BlockPos pos) { @@ -475,7 +517,7 @@ return chunk.getBlockState(pos); } -@@ -446,34 +720,53 @@ +@@ -446,34 +759,53 @@ this.pendingBlockEntityTickers.clear(); } @@ -527,18 +569,18 @@ + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + // Paper end - Prevent block entity and entity crashes } - } ++ } + // Paper start - Option to prevent armor stands from doing entity lookups + @Override + public boolean noCollision(@Nullable Entity entity, AABB box) { + if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; + return LevelAccessor.super.noCollision(entity, box); -+ } + } + // Paper end - Option to prevent armor stands from doing entity lookups public boolean shouldTickDeath(Entity entity) { return true; -@@ -510,13 +803,29 @@ +@@ -510,13 +842,29 @@ @Nullable @Override public BlockEntity getBlockEntity(BlockPos pos) { @@ -569,7 +611,7 @@ this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity); } } -@@ -643,7 +952,7 @@ +@@ -643,7 +991,7 @@ for (int k = 0; k < j; ++k) { EnderDragonPart entitycomplexpart = aentitycomplexpart[k]; @@ -578,7 +620,7 @@ if (t0 != null && predicate.test(t0)) { result.add(t0); -@@ -912,7 +1221,7 @@ +@@ -912,7 +1260,7 @@ public static enum ExplosionInteraction implements StringRepresentable { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 41c6a72603..474f330f38 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -1327,6 +1327,14 @@ public class CraftEventFactory { Projectile projectile = (Projectile) entity.getBukkitEntity(); org.bukkit.entity.Entity collided = position.getEntity().getBukkitEntity(); com.destroystokyo.paper.event.entity.ProjectileCollideEvent event = new com.destroystokyo.paper.event.entity.ProjectileCollideEvent(projectile, collided); + + if (projectile.getShooter() instanceof Player && collided instanceof Player) { + if (!((Player) projectile.getShooter()).canSee((Player) collided)) { + event.setCancelled(true); + return event; + } + } + Bukkit.getPluginManager().callEvent(event); return event; }